replicas-cli 0.3.73 → 0.3.75
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 +279 -145
- 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
|
}
|
|
@@ -23126,8 +23126,7 @@ var sendChatMessageRequestSchema = external_exports.object({
|
|
|
23126
23126
|
senderDisplayName: external_exports.string().optional(),
|
|
23127
23127
|
senderAvatarUrl: external_exports.string().optional(),
|
|
23128
23128
|
errorNotificationTarget: integrationErrorNotificationTargetSchema.optional(),
|
|
23129
|
-
errorNotificationTargets: external_exports.array(integrationErrorNotificationTargetSchema).optional()
|
|
23130
|
-
streamSlackActivity: external_exports.boolean().optional()
|
|
23129
|
+
errorNotificationTargets: external_exports.array(integrationErrorNotificationTargetSchema).optional()
|
|
23131
23130
|
}).passthrough();
|
|
23132
23131
|
function normalizeCodexAspTranscriptStatus(status, failed = false) {
|
|
23133
23132
|
if (failed || status === "failed" || status === "declined") return "failed";
|
|
@@ -23279,11 +23278,11 @@ function parseShellScript(script, cwd) {
|
|
|
23279
23278
|
parseUntil(scope, 0, false);
|
|
23280
23279
|
return scope.commands;
|
|
23281
23280
|
}
|
|
23282
|
-
function resolveShellPath(dir,
|
|
23283
|
-
if (
|
|
23284
|
-
if (!
|
|
23281
|
+
function resolveShellPath(dir, path8) {
|
|
23282
|
+
if (path8.includes(SHELL_OPAQUE) || path8.startsWith("~")) return null;
|
|
23283
|
+
if (!path8.startsWith("/") && dir === null) return null;
|
|
23285
23284
|
const parts = [];
|
|
23286
|
-
for (const part of (
|
|
23285
|
+
for (const part of (path8.startsWith("/") ? path8 : `${dir}/${path8}`).split("/")) {
|
|
23287
23286
|
if (part === "..") parts.pop();
|
|
23288
23287
|
else if (part && part !== ".") parts.push(part);
|
|
23289
23288
|
}
|
|
@@ -23637,8 +23636,8 @@ function parseSkillName(tool, input) {
|
|
|
23637
23636
|
const skillName = parsedInput.skill ?? parsedInput.name;
|
|
23638
23637
|
return typeof skillName === "string" && skillName ? skillName : null;
|
|
23639
23638
|
}
|
|
23640
|
-
function skillNameFromFilePath(
|
|
23641
|
-
const parts =
|
|
23639
|
+
function skillNameFromFilePath(path8) {
|
|
23640
|
+
const parts = path8.split(/[\\/]+/).filter(Boolean);
|
|
23642
23641
|
if (parts.length < 2 || parts[parts.length - 1].toLowerCase() !== "skill.md") return null;
|
|
23643
23642
|
const skillName = parts[parts.length - 2];
|
|
23644
23643
|
return /[*?[\]{}…$]/.test(skillName) || ["skills", ".system"].includes(skillName.toLowerCase()) ? null : skillName;
|
|
@@ -23648,19 +23647,19 @@ function skillFilePath(tool, input) {
|
|
|
23648
23647
|
if (!READ_TOOL_NAMES.has(tool.toLowerCase())) return null;
|
|
23649
23648
|
const parsedInput = typeof input === "string" ? safeJsonParse(input, null) : input;
|
|
23650
23649
|
if (!isRecord(parsedInput)) return null;
|
|
23651
|
-
const
|
|
23652
|
-
return
|
|
23650
|
+
const path8 = [parsedInput.path, parsedInput.filePath, parsedInput.file_path].find((value) => typeof value === "string" && value.length > 0);
|
|
23651
|
+
return path8 && skillNameFromFilePath(path8) ? path8 : null;
|
|
23653
23652
|
}
|
|
23654
23653
|
function createCallDisplayMessage(message2) {
|
|
23655
23654
|
if (message2.inputRequest) return { ...message2, type: "tool_call" };
|
|
23656
|
-
const
|
|
23657
|
-
const skillName = message2.server.toLowerCase() === "skills" ? message2.tool :
|
|
23655
|
+
const path8 = skillFilePath(message2.tool, message2.input);
|
|
23656
|
+
const skillName = message2.server.toLowerCase() === "skills" ? message2.tool : path8 ? skillNameFromFilePath(path8) : parseSkillName(message2.tool, message2.input);
|
|
23658
23657
|
if (skillName === null) return { ...message2, type: "tool_call" };
|
|
23659
23658
|
return {
|
|
23660
23659
|
id: message2.id,
|
|
23661
23660
|
type: "skill",
|
|
23662
23661
|
skillName,
|
|
23663
|
-
...
|
|
23662
|
+
...path8 ? { path: path8 } : {},
|
|
23664
23663
|
status: message2.status,
|
|
23665
23664
|
timestamp: message2.timestamp
|
|
23666
23665
|
};
|
|
@@ -23673,11 +23672,11 @@ function insertDisplayMessageByTimestamp(messages, message2) {
|
|
|
23673
23672
|
}
|
|
23674
23673
|
|
|
23675
23674
|
// ../shared/src/display-message/format.ts
|
|
23676
|
-
function fileContentDiff(
|
|
23675
|
+
function fileContentDiff(path8, content, action) {
|
|
23677
23676
|
const lines = content.replace(/\n$/, "").split("\n");
|
|
23678
23677
|
return [
|
|
23679
|
-
`--- ${action === "add" ? "/dev/null" : `a/${
|
|
23680
|
-
`+++ ${action === "add" ? `b/${
|
|
23678
|
+
`--- ${action === "add" ? "/dev/null" : `a/${path8}`}`,
|
|
23679
|
+
`+++ ${action === "add" ? `b/${path8}` : "/dev/null"}`,
|
|
23681
23680
|
action === "add" ? `@@ -0,0 +1,${lines.length} @@` : `@@ -1,${lines.length} +0,0 @@`,
|
|
23682
23681
|
...lines.map((line) => `${action === "add" ? "+" : "-"}${line}`)
|
|
23683
23682
|
].join("\n");
|
|
@@ -23704,7 +23703,7 @@ var LINE_COUNT_VALUE_FLAGS = /* @__PURE__ */ new Set([
|
|
|
23704
23703
|
]);
|
|
23705
23704
|
var SCRIPT_ROOT = "/";
|
|
23706
23705
|
var commandName = (argv) => argv[0].split("/").pop() ?? argv[0];
|
|
23707
|
-
var fileWrites = ({ writes }) => writes.filter(({ path:
|
|
23706
|
+
var fileWrites = ({ writes }) => writes.filter(({ path: path8 }) => path8 !== "/dev/null");
|
|
23708
23707
|
function shellCommands(command) {
|
|
23709
23708
|
return parseShellScript(command, SCRIPT_ROOT).filter(({ wrapper }) => !wrapper);
|
|
23710
23709
|
}
|
|
@@ -23716,8 +23715,8 @@ function skillNamesFromCommand(command) {
|
|
|
23716
23715
|
if (!SKILL_READ_COMMANDS.has(name) || writesFiles(name, argv) || fileWrites(shellCommand).length > 0) return [];
|
|
23717
23716
|
const paths = readCommandPaths(name, argv);
|
|
23718
23717
|
const stdinTarget = shellCommand.stdinTarget?.replaceAll(SHELL_OPAQUE, "\u2026");
|
|
23719
|
-
return (paths.length === 0 && stdinTarget ? [stdinTarget] : paths).flatMap((
|
|
23720
|
-
const resolved =
|
|
23718
|
+
return (paths.length === 0 && stdinTarget ? [stdinTarget] : paths).flatMap((path8) => {
|
|
23719
|
+
const resolved = path8.startsWith("~") ? path8 : resolveShellPath(shellCommand.dir, path8)?.replace(SCRIPT_ROOT, "");
|
|
23721
23720
|
const skillName = resolved && skillNameFromFilePath(resolved);
|
|
23722
23721
|
return skillName ? [skillName] : [];
|
|
23723
23722
|
});
|
|
@@ -24197,7 +24196,7 @@ Starts an ffmpeg screen recorder and returns only after ffmpeg has written the f
|
|
|
24197
24196
|
Only one recording at a time. Re-running \`start\` while one is active fails - call \`stop\` first.
|
|
24198
24197
|
|
|
24199
24198
|
### \`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.
|
|
24199
|
+
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
24200
|
|
|
24202
24201
|
## Patterns
|
|
24203
24202
|
|
|
@@ -24242,9 +24241,10 @@ For tasks the user wants proof of:
|
|
|
24242
24241
|
replicas computer record start /tmp/walkthrough.mp4
|
|
24243
24242
|
# ... your work ...
|
|
24244
24243
|
replicas computer record stop
|
|
24245
|
-
replicas media
|
|
24244
|
+
replicas media gif /tmp/walkthrough.mp4 --duration 8
|
|
24245
|
+
replicas media upload /tmp/walkthrough.gif /tmp/walkthrough.mp4 --name "Walkthrough" --name "Walkthrough recording"
|
|
24246
24246
|
\`\`\`
|
|
24247
|
-
Then embed the printed \`\`
|
|
24247
|
+
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
24248
|
|
|
24249
24249
|
## Failure modes
|
|
24250
24250
|
|
|
@@ -24886,7 +24886,7 @@ gh pr review 123 --request-changes --body "Changes needed"
|
|
|
24886
24886
|
|
|
24887
24887
|
## Media in GitHub workflows
|
|
24888
24888
|
|
|
24889
|
-
Media delivery is owned by \`references/MEDIA.md\`. Read
|
|
24889
|
+
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
24890
|
`;
|
|
24891
24891
|
var GITHUB_ABILITY = {
|
|
24892
24892
|
label: "GitHub",
|
|
@@ -25069,24 +25069,74 @@ var LINEAR_ABILITY = {
|
|
|
25069
25069
|
|
|
25070
25070
|
// ../shared/src/default-skills/replicas-agent/abilities/media.ts
|
|
25071
25071
|
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.
|
|
25072
|
+
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
25073
|
|
|
25074
25074
|
**Reference:** \`references/MEDIA.md\`
|
|
25075
25075
|
|
|
25076
25076
|
Use this when:
|
|
25077
25077
|
- You are about to run \`replicas media upload\`; this reference owns the complete Replicas-first, destination-second workflow
|
|
25078
25078
|
- You produce a screenshot, recording, generated image, or audio clip the user should see
|
|
25079
|
+
- 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
25080
|
- You produce a self-contained HTML report that should be linked from a pull request
|
|
25080
25081
|
- You record video output (browser automation, screen capture) \u2014 including the recommended aspect ratio and FPS
|
|
25081
25082
|
- 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)
|
|
25083
|
+
var REFERENCE7 = `# Media (Screenshots, GIFs, Recordings, Audio, HTML)
|
|
25083
25084
|
|
|
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).
|
|
25085
|
+
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
25086
|
|
|
25086
25087
|
## Prerequisites
|
|
25087
25088
|
|
|
25088
25089
|
The \`replicas\` CLI is pre-installed and authenticated in your workspace. No additional setup is needed.
|
|
25089
25090
|
|
|
25091
|
+
## Screenshot, GIF, or recording
|
|
25092
|
+
|
|
25093
|
+
Pick the format from what the reader has to see:
|
|
25094
|
+
|
|
25095
|
+
- **Static UI** (a layout, a new button, an error message): still screenshots.
|
|
25096
|
+
- **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.
|
|
25097
|
+
- **A long walkthrough, or anything with sound**: the MP4 recording, shown as a GIF or poster that links to it (see GitHub below).
|
|
25098
|
+
|
|
25099
|
+
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.
|
|
25100
|
+
|
|
25101
|
+
### Make a GIF from a recording
|
|
25102
|
+
|
|
25103
|
+
\`\`\`bash
|
|
25104
|
+
replicas computer record start /tmp/after.mp4 --fps 30
|
|
25105
|
+
# ... perform only the interaction ...
|
|
25106
|
+
replicas computer record stop
|
|
25107
|
+
replicas media gif /tmp/after.mp4 --start 1 --duration 6
|
|
25108
|
+
replicas media upload /tmp/after.gif --name "Language menu after fix"
|
|
25109
|
+
\`\`\`
|
|
25110
|
+
|
|
25111
|
+
\`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.
|
|
25112
|
+
|
|
25113
|
+
- Keep it to the interaction, usually 3\u201310 seconds: \`--start\` and \`--duration\` (default 10, max 30).
|
|
25114
|
+
- 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.
|
|
25115
|
+
- If it reports the GIF is still too large, show less: a shorter \`--duration\` or a tighter \`--crop\`.
|
|
25116
|
+
- Upload the GIF like any image. Its printed \`\` line is public and renders inline everywhere.
|
|
25117
|
+
- 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:
|
|
25118
|
+
|
|
25119
|
+
\`\`\`bash
|
|
25120
|
+
ffmpeg -v error -y -ss 1 -t 6 -i /tmp/after.mp4 \\
|
|
25121
|
+
-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" \\
|
|
25122
|
+
-loop 0 /tmp/after.gif
|
|
25123
|
+
\`\`\`
|
|
25124
|
+
|
|
25125
|
+
ffmpeg is baked into the workspace image. If it's missing, install it with \`sudo apt-get install -y ffmpeg\`.
|
|
25126
|
+
|
|
25127
|
+
### Before and after
|
|
25128
|
+
|
|
25129
|
+
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:
|
|
25130
|
+
|
|
25131
|
+
\`\`\`markdown
|
|
25132
|
+
The menu should open on its trigger. Before, it jumps about 95px up in half the openings.
|
|
25133
|
+
|
|
25134
|
+
| Before | After |
|
|
25135
|
+
| --- | --- |
|
|
25136
|
+
|  |  |
|
|
25137
|
+
| [View in Replicas](<before-dashboard-url>) | [View in Replicas](<after-dashboard-url>) |
|
|
25138
|
+
\`\`\`
|
|
25139
|
+
|
|
25090
25140
|
## When to upload
|
|
25091
25141
|
|
|
25092
25142
|
Upload to Replicas in these cases \u2014 and **only** these cases:
|
|
@@ -25113,7 +25163,7 @@ If none of these apply, don't upload.
|
|
|
25113
25163
|
| Slack | \`files.getUploadURLExternal\` \u2192 raw-byte POST \u2192 \`files.completeUploadExternal\` | Uploaded file in the channel or thread |
|
|
25114
25164
|
| Linear | \`fileUpload\` mutation \u2192 presigned upload \u2192 issue/comment mutation | Returned \`assetUrl\` in Markdown |
|
|
25115
25165
|
| 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 |
|
|
25166
|
+
| GitHub | Printed public embed for an image, GIF, or recording poster | Printed embed, linked to the recording when needed |
|
|
25117
25167
|
|
|
25118
25168
|
The dashboard link is the subtitle and jump-back path. It is never a substitute for the destination embed.
|
|
25119
25169
|
|
|
@@ -25318,7 +25368,7 @@ jq -n \\
|
|
|
25318
25368
|
}' | linear_graphql
|
|
25319
25369
|
\`\`\`
|
|
25320
25370
|
|
|
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>)\`.
|
|
25371
|
+
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
25372
|
|
|
25323
25373
|
The same flow works for issue bodies (use \`issueCreate\` / \`issueUpdate\` with the same markdown body).
|
|
25324
25374
|
|
|
@@ -25343,10 +25393,10 @@ gh pr edit 456 --body-file /tmp/pr-body.md
|
|
|
25343
25393
|
gh pr comment 456 --body-file /tmp/comment.md
|
|
25344
25394
|
\`\`\`
|
|
25345
25395
|
|
|
25346
|
-
|
|
25396
|
+
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
25397
|
|
|
25348
25398
|
\`\`\`markdown
|
|
25349
|
-
[](<recording-dashboard-url>)
|
|
25350
25400
|
\`\`\`
|
|
25351
25401
|
|
|
25352
25402
|
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 +25428,15 @@ const context = await browser.newContext({
|
|
|
25378
25428
|
|
|
25379
25429
|
For \`ffmpeg\` screen captures, pass \`-r 30\` (or \`-r 60\`) to set the frame rate.
|
|
25380
25430
|
|
|
25431
|
+
Start recording just before the interaction and stop right after it, so the GIF made from it stays short.
|
|
25432
|
+
|
|
25381
25433
|
## Supported formats
|
|
25382
25434
|
|
|
25383
25435
|
Auto-detected from the filename extension:
|
|
25384
25436
|
|
|
25385
25437
|
| Extension | Kind |
|
|
25386
25438
|
|---|---|
|
|
25387
|
-
| \`png\`, \`jpg\`, \`jpeg\`, \`webp\` | image |
|
|
25439
|
+
| \`png\`, \`jpg\`, \`jpeg\`, \`webp\`, \`gif\` | image |
|
|
25388
25440
|
| \`mp4\`, \`webm\` | video |
|
|
25389
25441
|
| \`mp3\`, \`wav\` | audio |
|
|
25390
25442
|
| \`html\`, \`htm\` | html |
|
|
@@ -25407,7 +25459,7 @@ replicas media upload chart-a.svg chart-b.svg --name "Latency chart" --name "Err
|
|
|
25407
25459
|
var MEDIA_ABILITY = {
|
|
25408
25460
|
label: "Media",
|
|
25409
25461
|
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",
|
|
25462
|
+
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
25463
|
section: SECTION7,
|
|
25412
25464
|
referenceFile: { name: "MEDIA.md", content: REFERENCE7 }
|
|
25413
25465
|
};
|
|
@@ -26392,7 +26444,7 @@ function stripAttachmentNote(text3) {
|
|
|
26392
26444
|
}
|
|
26393
26445
|
return {
|
|
26394
26446
|
content,
|
|
26395
|
-
files: match ? [...match[1].matchAll(/^- (.+)$/gm)].map(([,
|
|
26447
|
+
files: match ? [...match[1].matchAll(/^- (.+)$/gm)].map(([, path8]) => path8) : [],
|
|
26396
26448
|
walkthroughs
|
|
26397
26449
|
};
|
|
26398
26450
|
}
|
|
@@ -27278,7 +27330,7 @@ function parseOpencodeEvents(events) {
|
|
|
27278
27330
|
upsertDisplayMessage(messages, {
|
|
27279
27331
|
id,
|
|
27280
27332
|
type: "file_change",
|
|
27281
|
-
changes: files.map((
|
|
27333
|
+
changes: files.map((path8) => ({ path: path8, kind: "update" })),
|
|
27282
27334
|
status: "completed",
|
|
27283
27335
|
timestamp
|
|
27284
27336
|
});
|
|
@@ -28593,7 +28645,7 @@ var headlessAgentRequestSchema = external_exports.object({
|
|
|
28593
28645
|
});
|
|
28594
28646
|
|
|
28595
28647
|
// ../shared/src/cli-version.ts
|
|
28596
|
-
var CLI_VERSION = "0.3.
|
|
28648
|
+
var CLI_VERSION = "0.3.75";
|
|
28597
28649
|
|
|
28598
28650
|
// ../shared/src/version.ts
|
|
28599
28651
|
function compareVersions(v1, v2) {
|
|
@@ -31074,8 +31126,8 @@ async function claudeAuthCommand(options = {}) {
|
|
|
31074
31126
|
var CLIENT_ID = "1031625952748946";
|
|
31075
31127
|
var AUTH_URL = "https://auth.meta.com";
|
|
31076
31128
|
var API_KEY_URL = "https://api.meta.ai/muse-code/key";
|
|
31077
|
-
async function post(
|
|
31078
|
-
return fetch(`${AUTH_URL}${
|
|
31129
|
+
async function post(path8, body) {
|
|
31130
|
+
return fetch(`${AUTH_URL}${path8}`, {
|
|
31079
31131
|
method: "POST",
|
|
31080
31132
|
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
31081
31133
|
body
|
|
@@ -31271,7 +31323,7 @@ async function credentialsGetCommand(service, options) {
|
|
|
31271
31323
|
});
|
|
31272
31324
|
}
|
|
31273
31325
|
async function credentialsSetCommand(service, options) {
|
|
31274
|
-
const
|
|
31326
|
+
const path8 = credentialsPath(service, options, true);
|
|
31275
31327
|
const { org: org2, models, ...fields } = options;
|
|
31276
31328
|
const secretField = service === "bedrock" ? "aws_secret_access_key" : "api_key";
|
|
31277
31329
|
const body = {
|
|
@@ -31279,7 +31331,7 @@ async function credentialsSetCommand(service, options) {
|
|
|
31279
31331
|
...models ? { models: models.split(",").map((model2) => model2.trim()).filter(Boolean) } : {},
|
|
31280
31332
|
[secretField]: await readSecret(service, secretField === "api_key" ? "API key" : "AWS secret access key")
|
|
31281
31333
|
};
|
|
31282
|
-
const response = await orgAuthenticatedFetch(
|
|
31334
|
+
const response = await orgAuthenticatedFetch(path8, { method: "POST", body });
|
|
31283
31335
|
output(response, () => console.log(import_chalk17.default.green(`Saved ${scopeLabel(options)} ${service} credentials.`)));
|
|
31284
31336
|
}
|
|
31285
31337
|
async function credentialsRemoveCommand(service, options) {
|
|
@@ -32563,7 +32615,7 @@ async function canvasPutCommand(id, filename, options) {
|
|
|
32563
32615
|
|
|
32564
32616
|
// src/commands/chat.ts
|
|
32565
32617
|
var import_chalk23 = __toESM(require("chalk"));
|
|
32566
|
-
var chatPath2 = (id, chatId,
|
|
32618
|
+
var chatPath2 = (id, chatId, path8 = "") => `/v1/replica/${id}/chats/${chatId}${path8}`;
|
|
32567
32619
|
function printQueue(queue) {
|
|
32568
32620
|
if (queue.length === 0) {
|
|
32569
32621
|
console.log("Queue is empty.");
|
|
@@ -32648,8 +32700,8 @@ async function chatQueueListCommand(id, chatId) {
|
|
|
32648
32700
|
printQueue(queue);
|
|
32649
32701
|
});
|
|
32650
32702
|
}
|
|
32651
|
-
async function mutateQueue(
|
|
32652
|
-
output(await orgAuthenticatedFetch(
|
|
32703
|
+
async function mutateQueue(path8, method, body) {
|
|
32704
|
+
output(await orgAuthenticatedFetch(path8, { method, body }), ({ queue }) => {
|
|
32653
32705
|
if (queue) printQueue(queue);
|
|
32654
32706
|
else console.log("Done.");
|
|
32655
32707
|
});
|
|
@@ -32662,7 +32714,7 @@ var chatQueueActionCommand = (action) => (id, chatId, messageId) => mutateQueue(
|
|
|
32662
32714
|
|
|
32663
32715
|
// src/commands/plugins.ts
|
|
32664
32716
|
var import_chalk24 = __toESM(require("chalk"));
|
|
32665
|
-
var pluginsPath = async ({ env },
|
|
32717
|
+
var pluginsPath = async ({ env }, path8) => env ? `/v1/environments/${await resolveEnvironmentId(env)}/plugins${path8}` : `/v1/plugins${path8}`;
|
|
32666
32718
|
async function pluginsListCommand(options) {
|
|
32667
32719
|
output(await orgAuthenticatedFetch(await pluginsPath(options, "/connections")), ({ plugins: plugins2, environment: environment2 }) => {
|
|
32668
32720
|
if (!options.all && environment2.length === 0) console.log("No plugins connected. Pass --all to list available plugins.");
|
|
@@ -33717,10 +33769,10 @@ var import_chalk27 = __toESM(require("chalk"));
|
|
|
33717
33769
|
|
|
33718
33770
|
// src/lib/agent-api.ts
|
|
33719
33771
|
var ENGINE_PORT = process.env.REPLICAS_ENGINE_PORT || "3737";
|
|
33720
|
-
async function agentFetch(
|
|
33721
|
-
return (await agentRequest(
|
|
33772
|
+
async function agentFetch(path8, options) {
|
|
33773
|
+
return (await agentRequest(path8, options)).json();
|
|
33722
33774
|
}
|
|
33723
|
-
async function agentRequest(
|
|
33775
|
+
async function agentRequest(path8, options) {
|
|
33724
33776
|
const config3 = readAgentConfig();
|
|
33725
33777
|
if (!config3) {
|
|
33726
33778
|
throw new Error("Agent mode config not found");
|
|
@@ -33734,7 +33786,7 @@ async function agentRequest(path7, options) {
|
|
|
33734
33786
|
...options?.headers || {}
|
|
33735
33787
|
};
|
|
33736
33788
|
const body = options?.body === void 0 ? void 0 : isFormData ? options.body : JSON.stringify(options.body);
|
|
33737
|
-
const response = await fetch(`${MONOLITH_URL}${
|
|
33789
|
+
const response = await fetch(`${MONOLITH_URL}${path8}`, {
|
|
33738
33790
|
...options,
|
|
33739
33791
|
headers,
|
|
33740
33792
|
body
|
|
@@ -33745,7 +33797,7 @@ async function agentRequest(path7, options) {
|
|
|
33745
33797
|
}
|
|
33746
33798
|
return response;
|
|
33747
33799
|
}
|
|
33748
|
-
async function engineFetch(
|
|
33800
|
+
async function engineFetch(path8, options) {
|
|
33749
33801
|
const config3 = readAgentConfig();
|
|
33750
33802
|
if (!config3) {
|
|
33751
33803
|
throw new Error("Agent mode config not found");
|
|
@@ -33755,7 +33807,7 @@ async function engineFetch(path7, options) {
|
|
|
33755
33807
|
"Content-Type": "application/json",
|
|
33756
33808
|
...options?.headers || {}
|
|
33757
33809
|
};
|
|
33758
|
-
const response = await fetch(`http://localhost:${ENGINE_PORT}${
|
|
33810
|
+
const response = await fetch(`http://localhost:${ENGINE_PORT}${path8}`, {
|
|
33759
33811
|
...options,
|
|
33760
33812
|
headers,
|
|
33761
33813
|
body: options?.body !== void 0 ? JSON.stringify(options.body) : void 0
|
|
@@ -34028,6 +34080,87 @@ async function mediaUrlCommand(mediaId) {
|
|
|
34028
34080
|
output(response, ({ url: url2 }) => console.log(url2));
|
|
34029
34081
|
}
|
|
34030
34082
|
|
|
34083
|
+
// src/commands/media-gif.ts
|
|
34084
|
+
var import_child_process4 = require("child_process");
|
|
34085
|
+
var import_fs8 = __toESM(require("fs"));
|
|
34086
|
+
var import_path7 = __toESM(require("path"));
|
|
34087
|
+
var import_util3 = require("util");
|
|
34088
|
+
var GIF_MAX_BYTES = 5 * 1024 * 1024;
|
|
34089
|
+
var GIF_ATTEMPTS = 4;
|
|
34090
|
+
var execFileAsync = (0, import_util3.promisify)(import_child_process4.execFile);
|
|
34091
|
+
function parseOption(value, fallback, flag, min, max) {
|
|
34092
|
+
const parsed = value === void 0 ? fallback : Number(value);
|
|
34093
|
+
if (!Number.isFinite(parsed) || parsed < min || parsed > max) {
|
|
34094
|
+
throw new Error(`${flag} must be between ${min} and ${max}, got '${value}'`);
|
|
34095
|
+
}
|
|
34096
|
+
return parsed;
|
|
34097
|
+
}
|
|
34098
|
+
function gifFilter({ fps, width, crop }) {
|
|
34099
|
+
return [
|
|
34100
|
+
crop && `crop=${crop}`,
|
|
34101
|
+
`fps=${fps}`,
|
|
34102
|
+
`scale='min(${width},iw)':-1:flags=lanczos`,
|
|
34103
|
+
// stats_mode=diff spends the palette on what moves, and diff_mode=rectangle only re-encodes changed areas.
|
|
34104
|
+
"split[a][b];[a]palettegen=stats_mode=diff[p];[b][p]paletteuse=dither=bayer:bayer_scale=5:diff_mode=rectangle"
|
|
34105
|
+
].filter(Boolean).join(",");
|
|
34106
|
+
}
|
|
34107
|
+
async function mediaGifCommand(input, options) {
|
|
34108
|
+
const source = import_path7.default.resolve(input);
|
|
34109
|
+
if (!import_fs8.default.existsSync(source) || !import_fs8.default.statSync(source).isFile()) throw new Error(`File not found: ${source}`);
|
|
34110
|
+
const target = import_path7.default.resolve(options.output ?? `${source.replace(/\.[^./]+$/, "")}.gif`);
|
|
34111
|
+
if (import_path7.default.extname(target).toLowerCase() !== ".gif") throw new Error("--output must end in .gif");
|
|
34112
|
+
if (target === source) throw new Error("--output must differ from the input file");
|
|
34113
|
+
if (options.crop && !/^\d+:\d+:\d+:\d+$/.test(options.crop)) {
|
|
34114
|
+
throw new Error(`--crop must be width:height:x:y in pixels of the recording, got '${options.crop}'`);
|
|
34115
|
+
}
|
|
34116
|
+
const start = parseOption(options.start, 0, "--start", 0, 24 * 60 * 60);
|
|
34117
|
+
const duration3 = parseOption(options.duration, 10, "--duration", 1, 30);
|
|
34118
|
+
const maxWidth = parseOption(options.width, 960, "--width", 200, 1280);
|
|
34119
|
+
const maxFps = parseOption(options.fps, 12, "--fps", 5, 20);
|
|
34120
|
+
const temp = import_path7.default.join(import_path7.default.dirname(target), `.${import_path7.default.basename(target, ".gif")}.${process.pid}.tmp.gif`);
|
|
34121
|
+
let fps = maxFps;
|
|
34122
|
+
let width = maxWidth;
|
|
34123
|
+
try {
|
|
34124
|
+
for (let attempt = 0; attempt < GIF_ATTEMPTS; attempt++) {
|
|
34125
|
+
fps = Math.max(5, Math.round(maxFps * 0.8 ** attempt));
|
|
34126
|
+
width = Math.round(maxWidth * 0.8 ** attempt);
|
|
34127
|
+
await execFileAsync("ffmpeg", [
|
|
34128
|
+
"-v",
|
|
34129
|
+
"error",
|
|
34130
|
+
"-y",
|
|
34131
|
+
"-ss",
|
|
34132
|
+
String(start),
|
|
34133
|
+
"-t",
|
|
34134
|
+
String(duration3),
|
|
34135
|
+
"-i",
|
|
34136
|
+
source,
|
|
34137
|
+
"-vf",
|
|
34138
|
+
gifFilter({ fps, width, crop: options.crop }),
|
|
34139
|
+
"-loop",
|
|
34140
|
+
"0",
|
|
34141
|
+
temp
|
|
34142
|
+
], { timeout: 18e4 }).catch((error51) => {
|
|
34143
|
+
if (error51.code === "ENOENT") throw new Error("ffmpeg is not installed. Install it with `sudo apt-get install -y ffmpeg`.");
|
|
34144
|
+
throw new Error(`ffmpeg failed: ${error51.stderr?.trim() || error51.message}`);
|
|
34145
|
+
});
|
|
34146
|
+
const size = import_fs8.default.statSync(temp).size;
|
|
34147
|
+
if (size <= GIF_MAX_BYTES) {
|
|
34148
|
+
import_fs8.default.renameSync(temp, target);
|
|
34149
|
+
output({ path: target, size, fps, maxWidth: width, start, duration: duration3 }, () => {
|
|
34150
|
+
console.log(`GIF: ${target} (${(size / 1024 / 1024).toFixed(1)} MiB, ${fps} fps, up to ${width}px wide, ${duration3}s from ${start}s, loops)`);
|
|
34151
|
+
console.log(`Next: replicas media upload ${target} --name "<what it shows>", then paste the printed  line in your reply and the PR.`);
|
|
34152
|
+
});
|
|
34153
|
+
return;
|
|
34154
|
+
}
|
|
34155
|
+
}
|
|
34156
|
+
} finally {
|
|
34157
|
+
import_fs8.default.rmSync(temp, { force: true });
|
|
34158
|
+
}
|
|
34159
|
+
throw new Error(
|
|
34160
|
+
`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.`
|
|
34161
|
+
);
|
|
34162
|
+
}
|
|
34163
|
+
|
|
34031
34164
|
// src/commands/history.ts
|
|
34032
34165
|
var import_node_fs2 = require("fs");
|
|
34033
34166
|
var import_node_path2 = require("path");
|
|
@@ -34556,6 +34689,7 @@ if (isAgentMode()) {
|
|
|
34556
34689
|
service.command("stop <name>").description("Stop a service and its whole process group").action(run(serviceStopCommand));
|
|
34557
34690
|
service.command("list").description("List registered services and whether they are running").action(run(serviceListCommand));
|
|
34558
34691
|
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));
|
|
34692
|
+
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));
|
|
34559
34693
|
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(
|
|
34560
34694
|
"-n, --name <name>",
|
|
34561
34695
|
"Required human-facing display name shown in the dashboard. Pass one --name per file, in order.",
|