@amdahl/cli 0.4.1 → 0.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +63 -2
- package/dist/amdahl.js +789 -348
- package/package.json +1 -1
package/dist/amdahl.js
CHANGED
|
@@ -18,9 +18,9 @@ var __commonJS = (cb, mod) => function __require2() {
|
|
|
18
18
|
};
|
|
19
19
|
var __copyProps = (to, from, except, desc) => {
|
|
20
20
|
if (from && typeof from === "object" || typeof from === "function") {
|
|
21
|
-
for (let
|
|
22
|
-
if (!__hasOwnProp.call(to,
|
|
23
|
-
__defProp(to,
|
|
21
|
+
for (let key2 of __getOwnPropNames(from))
|
|
22
|
+
if (!__hasOwnProp.call(to, key2) && key2 !== except)
|
|
23
|
+
__defProp(to, key2, { get: () => from[key2], enumerable: !(desc = __getOwnPropDesc(from, key2)) || desc.enumerable });
|
|
24
24
|
}
|
|
25
25
|
return to;
|
|
26
26
|
};
|
|
@@ -110,11 +110,11 @@ var require_visit = __commonJS({
|
|
|
110
110
|
visit.BREAK = BREAK;
|
|
111
111
|
visit.SKIP = SKIP;
|
|
112
112
|
visit.REMOVE = REMOVE;
|
|
113
|
-
function visit_(
|
|
114
|
-
const ctrl = callVisitor(
|
|
113
|
+
function visit_(key2, node, visitor, path) {
|
|
114
|
+
const ctrl = callVisitor(key2, node, visitor, path);
|
|
115
115
|
if (identity.isNode(ctrl) || identity.isPair(ctrl)) {
|
|
116
|
-
replaceNode(
|
|
117
|
-
return visit_(
|
|
116
|
+
replaceNode(key2, path, ctrl);
|
|
117
|
+
return visit_(key2, ctrl, visitor, path);
|
|
118
118
|
}
|
|
119
119
|
if (typeof ctrl !== "symbol") {
|
|
120
120
|
if (identity.isCollection(node)) {
|
|
@@ -158,11 +158,11 @@ var require_visit = __commonJS({
|
|
|
158
158
|
visitAsync.BREAK = BREAK;
|
|
159
159
|
visitAsync.SKIP = SKIP;
|
|
160
160
|
visitAsync.REMOVE = REMOVE;
|
|
161
|
-
async function visitAsync_(
|
|
162
|
-
const ctrl = await callVisitor(
|
|
161
|
+
async function visitAsync_(key2, node, visitor, path) {
|
|
162
|
+
const ctrl = await callVisitor(key2, node, visitor, path);
|
|
163
163
|
if (identity.isNode(ctrl) || identity.isPair(ctrl)) {
|
|
164
|
-
replaceNode(
|
|
165
|
-
return visitAsync_(
|
|
164
|
+
replaceNode(key2, path, ctrl);
|
|
165
|
+
return visitAsync_(key2, ctrl, visitor, path);
|
|
166
166
|
}
|
|
167
167
|
if (typeof ctrl !== "symbol") {
|
|
168
168
|
if (identity.isCollection(node)) {
|
|
@@ -212,27 +212,27 @@ var require_visit = __commonJS({
|
|
|
212
212
|
}
|
|
213
213
|
return visitor;
|
|
214
214
|
}
|
|
215
|
-
function callVisitor(
|
|
215
|
+
function callVisitor(key2, node, visitor, path) {
|
|
216
216
|
if (typeof visitor === "function")
|
|
217
|
-
return visitor(
|
|
217
|
+
return visitor(key2, node, path);
|
|
218
218
|
if (identity.isMap(node))
|
|
219
|
-
return visitor.Map?.(
|
|
219
|
+
return visitor.Map?.(key2, node, path);
|
|
220
220
|
if (identity.isSeq(node))
|
|
221
|
-
return visitor.Seq?.(
|
|
221
|
+
return visitor.Seq?.(key2, node, path);
|
|
222
222
|
if (identity.isPair(node))
|
|
223
|
-
return visitor.Pair?.(
|
|
223
|
+
return visitor.Pair?.(key2, node, path);
|
|
224
224
|
if (identity.isScalar(node))
|
|
225
|
-
return visitor.Scalar?.(
|
|
225
|
+
return visitor.Scalar?.(key2, node, path);
|
|
226
226
|
if (identity.isAlias(node))
|
|
227
|
-
return visitor.Alias?.(
|
|
227
|
+
return visitor.Alias?.(key2, node, path);
|
|
228
228
|
return void 0;
|
|
229
229
|
}
|
|
230
|
-
function replaceNode(
|
|
230
|
+
function replaceNode(key2, path, node) {
|
|
231
231
|
const parent = path[path.length - 1];
|
|
232
232
|
if (identity.isCollection(parent)) {
|
|
233
|
-
parent.items[
|
|
233
|
+
parent.items[key2] = node;
|
|
234
234
|
} else if (identity.isPair(parent)) {
|
|
235
|
-
if (
|
|
235
|
+
if (key2 === "key")
|
|
236
236
|
parent.key = node;
|
|
237
237
|
else
|
|
238
238
|
parent.value = node;
|
|
@@ -307,8 +307,8 @@ var require_directives = __commonJS({
|
|
|
307
307
|
this.atNextDocument = false;
|
|
308
308
|
}
|
|
309
309
|
const parts = line.trim().split(/[ \t]+/);
|
|
310
|
-
const
|
|
311
|
-
switch (
|
|
310
|
+
const name2 = parts.shift();
|
|
311
|
+
switch (name2) {
|
|
312
312
|
case "%TAG": {
|
|
313
313
|
if (parts.length !== 2) {
|
|
314
314
|
onError(0, "%TAG directive should contain exactly two parts");
|
|
@@ -336,7 +336,7 @@ var require_directives = __commonJS({
|
|
|
336
336
|
}
|
|
337
337
|
}
|
|
338
338
|
default:
|
|
339
|
-
onError(0, `Unknown directive ${
|
|
339
|
+
onError(0, `Unknown directive ${name2}`, true);
|
|
340
340
|
return false;
|
|
341
341
|
}
|
|
342
342
|
}
|
|
@@ -445,9 +445,9 @@ var require_anchors = __commonJS({
|
|
|
445
445
|
}
|
|
446
446
|
function findNewAnchor(prefix2, exclude) {
|
|
447
447
|
for (let i = 1; true; ++i) {
|
|
448
|
-
const
|
|
449
|
-
if (!exclude.has(
|
|
450
|
-
return
|
|
448
|
+
const name2 = `${prefix2}${i}`;
|
|
449
|
+
if (!exclude.has(name2))
|
|
450
|
+
return name2;
|
|
451
451
|
}
|
|
452
452
|
}
|
|
453
453
|
function createNodeAnchors(doc, prefix2) {
|
|
@@ -493,7 +493,7 @@ var require_anchors = __commonJS({
|
|
|
493
493
|
var require_applyReviver = __commonJS({
|
|
494
494
|
"node_modules/.pnpm/yaml@2.9.1/node_modules/yaml/dist/doc/applyReviver.js"(exports) {
|
|
495
495
|
"use strict";
|
|
496
|
-
function applyReviver(reviver, obj,
|
|
496
|
+
function applyReviver(reviver, obj, key2, val) {
|
|
497
497
|
if (val && typeof val === "object") {
|
|
498
498
|
if (Array.isArray(val)) {
|
|
499
499
|
for (let i = 0, len = val.length; i < len; ++i) {
|
|
@@ -533,7 +533,7 @@ var require_applyReviver = __commonJS({
|
|
|
533
533
|
}
|
|
534
534
|
}
|
|
535
535
|
}
|
|
536
|
-
return reviver.call(obj,
|
|
536
|
+
return reviver.call(obj, key2, val);
|
|
537
537
|
}
|
|
538
538
|
exports.applyReviver = applyReviver;
|
|
539
539
|
}
|
|
@@ -896,14 +896,14 @@ var require_Collection = __commonJS({
|
|
|
896
896
|
if (isEmptyPath(path))
|
|
897
897
|
this.add(value);
|
|
898
898
|
else {
|
|
899
|
-
const [
|
|
900
|
-
const node = this.get(
|
|
899
|
+
const [key2, ...rest] = path;
|
|
900
|
+
const node = this.get(key2, true);
|
|
901
901
|
if (identity.isCollection(node))
|
|
902
902
|
node.addIn(rest, value);
|
|
903
903
|
else if (node === void 0 && this.schema)
|
|
904
|
-
this.set(
|
|
904
|
+
this.set(key2, collectionFromPath(this.schema, rest, value));
|
|
905
905
|
else
|
|
906
|
-
throw new Error(`Expected YAML collection at ${
|
|
906
|
+
throw new Error(`Expected YAML collection at ${key2}. Remaining path: ${rest}`);
|
|
907
907
|
}
|
|
908
908
|
}
|
|
909
909
|
/**
|
|
@@ -911,14 +911,14 @@ var require_Collection = __commonJS({
|
|
|
911
911
|
* @returns `true` if the item was found and removed.
|
|
912
912
|
*/
|
|
913
913
|
deleteIn(path) {
|
|
914
|
-
const [
|
|
914
|
+
const [key2, ...rest] = path;
|
|
915
915
|
if (rest.length === 0)
|
|
916
|
-
return this.delete(
|
|
917
|
-
const node = this.get(
|
|
916
|
+
return this.delete(key2);
|
|
917
|
+
const node = this.get(key2, true);
|
|
918
918
|
if (identity.isCollection(node))
|
|
919
919
|
return node.deleteIn(rest);
|
|
920
920
|
else
|
|
921
|
-
throw new Error(`Expected YAML collection at ${
|
|
921
|
+
throw new Error(`Expected YAML collection at ${key2}. Remaining path: ${rest}`);
|
|
922
922
|
}
|
|
923
923
|
/**
|
|
924
924
|
* Returns item at `key`, or `undefined` if not found. By default unwraps
|
|
@@ -926,8 +926,8 @@ var require_Collection = __commonJS({
|
|
|
926
926
|
* `true` (collections are always returned intact).
|
|
927
927
|
*/
|
|
928
928
|
getIn(path, keepScalar) {
|
|
929
|
-
const [
|
|
930
|
-
const node = this.get(
|
|
929
|
+
const [key2, ...rest] = path;
|
|
930
|
+
const node = this.get(key2, true);
|
|
931
931
|
if (rest.length === 0)
|
|
932
932
|
return !keepScalar && identity.isScalar(node) ? node.value : node;
|
|
933
933
|
else
|
|
@@ -945,10 +945,10 @@ var require_Collection = __commonJS({
|
|
|
945
945
|
* Checks if the collection includes a value with the key `key`.
|
|
946
946
|
*/
|
|
947
947
|
hasIn(path) {
|
|
948
|
-
const [
|
|
948
|
+
const [key2, ...rest] = path;
|
|
949
949
|
if (rest.length === 0)
|
|
950
|
-
return this.has(
|
|
951
|
-
const node = this.get(
|
|
950
|
+
return this.has(key2);
|
|
951
|
+
const node = this.get(key2, true);
|
|
952
952
|
return identity.isCollection(node) ? node.hasIn(rest) : false;
|
|
953
953
|
}
|
|
954
954
|
/**
|
|
@@ -956,17 +956,17 @@ var require_Collection = __commonJS({
|
|
|
956
956
|
* boolean to add/remove the item from the set.
|
|
957
957
|
*/
|
|
958
958
|
setIn(path, value) {
|
|
959
|
-
const [
|
|
959
|
+
const [key2, ...rest] = path;
|
|
960
960
|
if (rest.length === 0) {
|
|
961
|
-
this.set(
|
|
961
|
+
this.set(key2, value);
|
|
962
962
|
} else {
|
|
963
|
-
const node = this.get(
|
|
963
|
+
const node = this.get(key2, true);
|
|
964
964
|
if (identity.isCollection(node))
|
|
965
965
|
node.setIn(rest, value);
|
|
966
966
|
else if (node === void 0 && this.schema)
|
|
967
|
-
this.set(
|
|
967
|
+
this.set(key2, collectionFromPath(this.schema, rest, value));
|
|
968
968
|
else
|
|
969
|
-
throw new Error(`Expected YAML collection at ${
|
|
969
|
+
throw new Error(`Expected YAML collection at ${key2}. Remaining path: ${rest}`);
|
|
970
970
|
}
|
|
971
971
|
}
|
|
972
972
|
};
|
|
@@ -1484,8 +1484,8 @@ var require_stringify = __commonJS({
|
|
|
1484
1484
|
tagObj = tags.find((t) => t.nodeClass && obj instanceof t.nodeClass);
|
|
1485
1485
|
}
|
|
1486
1486
|
if (!tagObj) {
|
|
1487
|
-
const
|
|
1488
|
-
throw new Error(`Tag not resolved for ${
|
|
1487
|
+
const name2 = obj?.constructor?.name ?? (obj === null ? "null" : typeof obj);
|
|
1488
|
+
throw new Error(`Tag not resolved for ${name2} value`);
|
|
1489
1489
|
}
|
|
1490
1490
|
return tagObj;
|
|
1491
1491
|
}
|
|
@@ -1544,19 +1544,19 @@ var require_stringifyPair = __commonJS({
|
|
|
1544
1544
|
var Scalar = require_Scalar();
|
|
1545
1545
|
var stringify = require_stringify();
|
|
1546
1546
|
var stringifyComment = require_stringifyComment();
|
|
1547
|
-
function stringifyPair({ key, value }, ctx, onComment, onChompKeep) {
|
|
1547
|
+
function stringifyPair({ key: key2, value }, ctx, onComment, onChompKeep) {
|
|
1548
1548
|
const { allNullValues, doc, indent, indentStep, options: { commentString, indentSeq, simpleKeys } } = ctx;
|
|
1549
|
-
let keyComment = identity.isNode(
|
|
1549
|
+
let keyComment = identity.isNode(key2) && key2.comment || null;
|
|
1550
1550
|
if (simpleKeys) {
|
|
1551
1551
|
if (keyComment) {
|
|
1552
1552
|
throw new Error("With simple keys, key nodes cannot have comments");
|
|
1553
1553
|
}
|
|
1554
|
-
if (identity.isCollection(
|
|
1554
|
+
if (identity.isCollection(key2) || !identity.isNode(key2) && typeof key2 === "object") {
|
|
1555
1555
|
const msg = "With simple keys, collection cannot be used as a key value";
|
|
1556
1556
|
throw new Error(msg);
|
|
1557
1557
|
}
|
|
1558
1558
|
}
|
|
1559
|
-
let explicitKey = !simpleKeys && (!
|
|
1559
|
+
let explicitKey = !simpleKeys && (!key2 || keyComment && value == null && !ctx.inFlow || identity.isCollection(key2) || (identity.isScalar(key2) ? key2.type === Scalar.Scalar.BLOCK_FOLDED || key2.type === Scalar.Scalar.BLOCK_LITERAL : typeof key2 === "object"));
|
|
1560
1560
|
ctx = Object.assign({}, ctx, {
|
|
1561
1561
|
allNullValues: false,
|
|
1562
1562
|
implicitKey: !explicitKey && (simpleKeys || !allNullValues),
|
|
@@ -1564,7 +1564,7 @@ var require_stringifyPair = __commonJS({
|
|
|
1564
1564
|
});
|
|
1565
1565
|
let keyCommentDone = false;
|
|
1566
1566
|
let chompKeep = false;
|
|
1567
|
-
let str2 = stringify.stringify(
|
|
1567
|
+
let str2 = stringify.stringify(key2, ctx, () => keyCommentDone = true, () => chompKeep = true);
|
|
1568
1568
|
if (!explicitKey && !ctx.inFlow && str2.length > 1024) {
|
|
1569
1569
|
if (simpleKeys)
|
|
1570
1570
|
throw new Error("With simple keys, single line scalar must not span more than 1024 characters");
|
|
@@ -1708,7 +1708,7 @@ var require_merge = __commonJS({
|
|
|
1708
1708
|
}),
|
|
1709
1709
|
stringify: () => MERGE_KEY
|
|
1710
1710
|
};
|
|
1711
|
-
var isMergeKey = (ctx,
|
|
1711
|
+
var isMergeKey = (ctx, key2) => (merge.identify(key2) || identity.isScalar(key2) && (!key2.type || key2.type === Scalar.Scalar.PLAIN) && merge.identify(key2.value)) && ctx?.doc.schema.tags.some((tag) => tag.tag === merge.tag && tag.default);
|
|
1712
1712
|
function addMergeToJSMap(ctx, map, value) {
|
|
1713
1713
|
const source = resolveAliasValue(ctx, value);
|
|
1714
1714
|
if (identity.isSeq(source))
|
|
@@ -1725,14 +1725,14 @@ var require_merge = __commonJS({
|
|
|
1725
1725
|
if (!identity.isMap(source))
|
|
1726
1726
|
throw new Error("Merge sources must be maps or map aliases");
|
|
1727
1727
|
const srcMap = source.toJSON(null, ctx, Map);
|
|
1728
|
-
for (const [
|
|
1728
|
+
for (const [key2, value2] of srcMap) {
|
|
1729
1729
|
if (map instanceof Map) {
|
|
1730
|
-
if (!map.has(
|
|
1731
|
-
map.set(
|
|
1730
|
+
if (!map.has(key2))
|
|
1731
|
+
map.set(key2, value2);
|
|
1732
1732
|
} else if (map instanceof Set) {
|
|
1733
|
-
map.add(
|
|
1734
|
-
} else if (!Object.prototype.hasOwnProperty.call(map,
|
|
1735
|
-
Object.defineProperty(map,
|
|
1733
|
+
map.add(key2);
|
|
1734
|
+
} else if (!Object.prototype.hasOwnProperty.call(map, key2)) {
|
|
1735
|
+
Object.defineProperty(map, key2, {
|
|
1736
1736
|
value: value2,
|
|
1737
1737
|
writable: true,
|
|
1738
1738
|
enumerable: true,
|
|
@@ -1760,19 +1760,19 @@ var require_addPairToJSMap = __commonJS({
|
|
|
1760
1760
|
var stringify = require_stringify();
|
|
1761
1761
|
var identity = require_identity();
|
|
1762
1762
|
var toJS = require_toJS();
|
|
1763
|
-
function addPairToJSMap(ctx, map, { key, value }) {
|
|
1764
|
-
if (identity.isNode(
|
|
1765
|
-
|
|
1766
|
-
else if (merge.isMergeKey(ctx,
|
|
1763
|
+
function addPairToJSMap(ctx, map, { key: key2, value }) {
|
|
1764
|
+
if (identity.isNode(key2) && key2.addToJSMap)
|
|
1765
|
+
key2.addToJSMap(ctx, map, value);
|
|
1766
|
+
else if (merge.isMergeKey(ctx, key2))
|
|
1767
1767
|
merge.addMergeToJSMap(ctx, map, value);
|
|
1768
1768
|
else {
|
|
1769
|
-
const jsKey = toJS.toJS(
|
|
1769
|
+
const jsKey = toJS.toJS(key2, "", ctx);
|
|
1770
1770
|
if (map instanceof Map) {
|
|
1771
1771
|
map.set(jsKey, toJS.toJS(value, jsKey, ctx));
|
|
1772
1772
|
} else if (map instanceof Set) {
|
|
1773
1773
|
map.add(jsKey);
|
|
1774
1774
|
} else {
|
|
1775
|
-
const stringKey = stringifyKey(
|
|
1775
|
+
const stringKey = stringifyKey(key2, jsKey, ctx);
|
|
1776
1776
|
const jsValue = toJS.toJS(value, stringKey, ctx);
|
|
1777
1777
|
if (stringKey in map)
|
|
1778
1778
|
Object.defineProperty(map, stringKey, {
|
|
@@ -1787,19 +1787,19 @@ var require_addPairToJSMap = __commonJS({
|
|
|
1787
1787
|
}
|
|
1788
1788
|
return map;
|
|
1789
1789
|
}
|
|
1790
|
-
function stringifyKey(
|
|
1790
|
+
function stringifyKey(key2, jsKey, ctx) {
|
|
1791
1791
|
if (jsKey === null)
|
|
1792
1792
|
return "";
|
|
1793
1793
|
if (typeof jsKey !== "object")
|
|
1794
1794
|
return String(jsKey);
|
|
1795
|
-
if (identity.isNode(
|
|
1795
|
+
if (identity.isNode(key2) && ctx?.doc) {
|
|
1796
1796
|
const strCtx = stringify.createStringifyContext(ctx.doc, {});
|
|
1797
1797
|
strCtx.anchors = /* @__PURE__ */ new Set();
|
|
1798
1798
|
for (const node of ctx.anchors.keys())
|
|
1799
1799
|
strCtx.anchors.add(node.anchor);
|
|
1800
1800
|
strCtx.inFlow = true;
|
|
1801
1801
|
strCtx.inStringifyKey = true;
|
|
1802
|
-
const strKey =
|
|
1802
|
+
const strKey = key2.toString(strCtx);
|
|
1803
1803
|
if (!ctx.mapKeyWarned) {
|
|
1804
1804
|
let jsonStr = JSON.stringify(strKey);
|
|
1805
1805
|
if (jsonStr.length > 40)
|
|
@@ -1823,24 +1823,24 @@ var require_Pair = __commonJS({
|
|
|
1823
1823
|
var stringifyPair = require_stringifyPair();
|
|
1824
1824
|
var addPairToJSMap = require_addPairToJSMap();
|
|
1825
1825
|
var identity = require_identity();
|
|
1826
|
-
function createPair(
|
|
1827
|
-
const k = createNode.createNode(
|
|
1826
|
+
function createPair(key2, value, ctx) {
|
|
1827
|
+
const k = createNode.createNode(key2, void 0, ctx);
|
|
1828
1828
|
const v = createNode.createNode(value, void 0, ctx);
|
|
1829
1829
|
return new Pair(k, v);
|
|
1830
1830
|
}
|
|
1831
1831
|
var Pair = class _Pair {
|
|
1832
|
-
constructor(
|
|
1832
|
+
constructor(key2, value = null) {
|
|
1833
1833
|
Object.defineProperty(this, identity.NODE_TYPE, { value: identity.PAIR });
|
|
1834
|
-
this.key =
|
|
1834
|
+
this.key = key2;
|
|
1835
1835
|
this.value = value;
|
|
1836
1836
|
}
|
|
1837
1837
|
clone(schema) {
|
|
1838
|
-
let { key, value } = this;
|
|
1839
|
-
if (identity.isNode(
|
|
1840
|
-
|
|
1838
|
+
let { key: key2, value } = this;
|
|
1839
|
+
if (identity.isNode(key2))
|
|
1840
|
+
key2 = key2.clone(schema);
|
|
1841
1841
|
if (identity.isNode(value))
|
|
1842
1842
|
value = value.clone(schema);
|
|
1843
|
-
return new _Pair(
|
|
1843
|
+
return new _Pair(key2, value);
|
|
1844
1844
|
}
|
|
1845
1845
|
toJSON(_, ctx) {
|
|
1846
1846
|
const pair = ctx?.mapAsMap ? /* @__PURE__ */ new Map() : {};
|
|
@@ -2016,11 +2016,11 @@ var require_YAMLMap = __commonJS({
|
|
|
2016
2016
|
var identity = require_identity();
|
|
2017
2017
|
var Pair = require_Pair();
|
|
2018
2018
|
var Scalar = require_Scalar();
|
|
2019
|
-
function findPair(items,
|
|
2020
|
-
const k = identity.isScalar(
|
|
2019
|
+
function findPair(items, key2) {
|
|
2020
|
+
const k = identity.isScalar(key2) ? key2.value : key2;
|
|
2021
2021
|
for (const it of items) {
|
|
2022
2022
|
if (identity.isPair(it)) {
|
|
2023
|
-
if (it.key ===
|
|
2023
|
+
if (it.key === key2 || it.key === k)
|
|
2024
2024
|
return it;
|
|
2025
2025
|
if (identity.isScalar(it.key) && it.key.value === k)
|
|
2026
2026
|
return it;
|
|
@@ -2043,20 +2043,20 @@ var require_YAMLMap = __commonJS({
|
|
|
2043
2043
|
static from(schema, obj, ctx) {
|
|
2044
2044
|
const { keepUndefined, replacer } = ctx;
|
|
2045
2045
|
const map = new this(schema);
|
|
2046
|
-
const add = (
|
|
2046
|
+
const add = (key2, value) => {
|
|
2047
2047
|
if (typeof replacer === "function")
|
|
2048
|
-
value = replacer.call(obj,
|
|
2049
|
-
else if (Array.isArray(replacer) && !replacer.includes(
|
|
2048
|
+
value = replacer.call(obj, key2, value);
|
|
2049
|
+
else if (Array.isArray(replacer) && !replacer.includes(key2))
|
|
2050
2050
|
return;
|
|
2051
2051
|
if (value !== void 0 || keepUndefined)
|
|
2052
|
-
map.items.push(Pair.createPair(
|
|
2052
|
+
map.items.push(Pair.createPair(key2, value, ctx));
|
|
2053
2053
|
};
|
|
2054
2054
|
if (obj instanceof Map) {
|
|
2055
|
-
for (const [
|
|
2056
|
-
add(
|
|
2055
|
+
for (const [key2, value] of obj)
|
|
2056
|
+
add(key2, value);
|
|
2057
2057
|
} else if (obj && typeof obj === "object") {
|
|
2058
|
-
for (const
|
|
2059
|
-
add(
|
|
2058
|
+
for (const key2 of Object.keys(obj))
|
|
2059
|
+
add(key2, obj[key2]);
|
|
2060
2060
|
}
|
|
2061
2061
|
if (typeof schema.sortMapEntries === "function") {
|
|
2062
2062
|
map.items.sort(schema.sortMapEntries);
|
|
@@ -2096,23 +2096,23 @@ var require_YAMLMap = __commonJS({
|
|
|
2096
2096
|
this.items.push(_pair);
|
|
2097
2097
|
}
|
|
2098
2098
|
}
|
|
2099
|
-
delete(
|
|
2100
|
-
const it = findPair(this.items,
|
|
2099
|
+
delete(key2) {
|
|
2100
|
+
const it = findPair(this.items, key2);
|
|
2101
2101
|
if (!it)
|
|
2102
2102
|
return false;
|
|
2103
2103
|
const del = this.items.splice(this.items.indexOf(it), 1);
|
|
2104
2104
|
return del.length > 0;
|
|
2105
2105
|
}
|
|
2106
|
-
get(
|
|
2107
|
-
const it = findPair(this.items,
|
|
2106
|
+
get(key2, keepScalar) {
|
|
2107
|
+
const it = findPair(this.items, key2);
|
|
2108
2108
|
const node = it?.value;
|
|
2109
2109
|
return (!keepScalar && identity.isScalar(node) ? node.value : node) ?? void 0;
|
|
2110
2110
|
}
|
|
2111
|
-
has(
|
|
2112
|
-
return !!findPair(this.items,
|
|
2111
|
+
has(key2) {
|
|
2112
|
+
return !!findPair(this.items, key2);
|
|
2113
2113
|
}
|
|
2114
|
-
set(
|
|
2115
|
-
this.add(new Pair.Pair(
|
|
2114
|
+
set(key2, value) {
|
|
2115
|
+
this.add(new Pair.Pair(key2, value), true);
|
|
2116
2116
|
}
|
|
2117
2117
|
/**
|
|
2118
2118
|
* @param ctx - Conversion context, originally set in Document#toJS()
|
|
@@ -2201,15 +2201,15 @@ var require_YAMLSeq = __commonJS({
|
|
|
2201
2201
|
*
|
|
2202
2202
|
* @returns `true` if the item was found and removed.
|
|
2203
2203
|
*/
|
|
2204
|
-
delete(
|
|
2205
|
-
const idx = asItemIndex(
|
|
2204
|
+
delete(key2) {
|
|
2205
|
+
const idx = asItemIndex(key2);
|
|
2206
2206
|
if (typeof idx !== "number")
|
|
2207
2207
|
return false;
|
|
2208
2208
|
const del = this.items.splice(idx, 1);
|
|
2209
2209
|
return del.length > 0;
|
|
2210
2210
|
}
|
|
2211
|
-
get(
|
|
2212
|
-
const idx = asItemIndex(
|
|
2211
|
+
get(key2, keepScalar) {
|
|
2212
|
+
const idx = asItemIndex(key2);
|
|
2213
2213
|
if (typeof idx !== "number")
|
|
2214
2214
|
return void 0;
|
|
2215
2215
|
const it = this.items[idx];
|
|
@@ -2221,8 +2221,8 @@ var require_YAMLSeq = __commonJS({
|
|
|
2221
2221
|
* `key` must contain a representation of an integer for this to succeed.
|
|
2222
2222
|
* It may be wrapped in a `Scalar`.
|
|
2223
2223
|
*/
|
|
2224
|
-
has(
|
|
2225
|
-
const idx = asItemIndex(
|
|
2224
|
+
has(key2) {
|
|
2225
|
+
const idx = asItemIndex(key2);
|
|
2226
2226
|
return typeof idx === "number" && idx < this.items.length;
|
|
2227
2227
|
}
|
|
2228
2228
|
/**
|
|
@@ -2232,10 +2232,10 @@ var require_YAMLSeq = __commonJS({
|
|
|
2232
2232
|
* If `key` does not contain a representation of an integer, this will throw.
|
|
2233
2233
|
* It may be wrapped in a `Scalar`.
|
|
2234
2234
|
*/
|
|
2235
|
-
set(
|
|
2236
|
-
const idx = asItemIndex(
|
|
2235
|
+
set(key2, value) {
|
|
2236
|
+
const idx = asItemIndex(key2);
|
|
2237
2237
|
if (typeof idx !== "number")
|
|
2238
|
-
throw new Error(`Expected a valid index, not ${
|
|
2238
|
+
throw new Error(`Expected a valid index, not ${key2}.`);
|
|
2239
2239
|
const prev = this.items[idx];
|
|
2240
2240
|
if (identity.isScalar(prev) && Scalar.isScalarValue(value))
|
|
2241
2241
|
prev.value = value;
|
|
@@ -2269,8 +2269,8 @@ var require_YAMLSeq = __commonJS({
|
|
|
2269
2269
|
let i = 0;
|
|
2270
2270
|
for (let it of obj) {
|
|
2271
2271
|
if (typeof replacer === "function") {
|
|
2272
|
-
const
|
|
2273
|
-
it = replacer.call(obj,
|
|
2272
|
+
const key2 = obj instanceof Set ? it : String(i++);
|
|
2273
|
+
it = replacer.call(obj, key2, it);
|
|
2274
2274
|
}
|
|
2275
2275
|
seq.items.push(createNode.createNode(it, void 0, ctx));
|
|
2276
2276
|
}
|
|
@@ -2278,8 +2278,8 @@ var require_YAMLSeq = __commonJS({
|
|
|
2278
2278
|
return seq;
|
|
2279
2279
|
}
|
|
2280
2280
|
};
|
|
2281
|
-
function asItemIndex(
|
|
2282
|
-
let idx = identity.isScalar(
|
|
2281
|
+
function asItemIndex(key2) {
|
|
2282
|
+
let idx = identity.isScalar(key2) ? key2.value : key2;
|
|
2283
2283
|
if (idx && typeof idx === "string")
|
|
2284
2284
|
idx = Number(idx);
|
|
2285
2285
|
return typeof idx === "number" && Number.isInteger(idx) && idx >= 0 ? idx : null;
|
|
@@ -2693,25 +2693,25 @@ ${cn.comment}` : item.comment;
|
|
|
2693
2693
|
for (let it of iterable) {
|
|
2694
2694
|
if (typeof replacer === "function")
|
|
2695
2695
|
it = replacer.call(iterable, String(i++), it);
|
|
2696
|
-
let
|
|
2696
|
+
let key2, value;
|
|
2697
2697
|
if (Array.isArray(it)) {
|
|
2698
2698
|
if (it.length === 2) {
|
|
2699
|
-
|
|
2699
|
+
key2 = it[0];
|
|
2700
2700
|
value = it[1];
|
|
2701
2701
|
} else
|
|
2702
2702
|
throw new TypeError(`Expected [key, value] tuple: ${it}`);
|
|
2703
2703
|
} else if (it && it instanceof Object) {
|
|
2704
2704
|
const keys = Object.keys(it);
|
|
2705
2705
|
if (keys.length === 1) {
|
|
2706
|
-
|
|
2707
|
-
value = it[
|
|
2706
|
+
key2 = keys[0];
|
|
2707
|
+
value = it[key2];
|
|
2708
2708
|
} else {
|
|
2709
2709
|
throw new TypeError(`Expected tuple with one key, not ${keys.length} keys`);
|
|
2710
2710
|
}
|
|
2711
2711
|
} else {
|
|
2712
|
-
|
|
2712
|
+
key2 = it;
|
|
2713
2713
|
}
|
|
2714
|
-
pairs2.items.push(Pair.createPair(
|
|
2714
|
+
pairs2.items.push(Pair.createPair(key2, value, ctx));
|
|
2715
2715
|
}
|
|
2716
2716
|
return pairs2;
|
|
2717
2717
|
}
|
|
@@ -2758,16 +2758,16 @@ var require_omap = __commonJS({
|
|
|
2758
2758
|
if (ctx?.onCreate)
|
|
2759
2759
|
ctx.onCreate(map);
|
|
2760
2760
|
for (const pair of this.items) {
|
|
2761
|
-
let
|
|
2761
|
+
let key2, value;
|
|
2762
2762
|
if (identity.isPair(pair)) {
|
|
2763
|
-
|
|
2764
|
-
value = toJS.toJS(pair.value,
|
|
2763
|
+
key2 = toJS.toJS(pair.key, "", ctx);
|
|
2764
|
+
value = toJS.toJS(pair.value, key2, ctx);
|
|
2765
2765
|
} else {
|
|
2766
|
-
|
|
2766
|
+
key2 = toJS.toJS(pair, "", ctx);
|
|
2767
2767
|
}
|
|
2768
|
-
if (map.has(
|
|
2768
|
+
if (map.has(key2))
|
|
2769
2769
|
throw new Error("Ordered maps must not include duplicate keys");
|
|
2770
|
-
map.set(
|
|
2770
|
+
map.set(key2, value);
|
|
2771
2771
|
}
|
|
2772
2772
|
return map;
|
|
2773
2773
|
}
|
|
@@ -2788,12 +2788,12 @@ var require_omap = __commonJS({
|
|
|
2788
2788
|
resolve(seq, onError) {
|
|
2789
2789
|
const pairs$1 = pairs.resolvePairs(seq, onError);
|
|
2790
2790
|
const seenKeys = [];
|
|
2791
|
-
for (const { key } of pairs$1.items) {
|
|
2792
|
-
if (identity.isScalar(
|
|
2793
|
-
if (seenKeys.includes(
|
|
2794
|
-
onError(`Ordered maps must not include duplicate keys: ${
|
|
2791
|
+
for (const { key: key2 } of pairs$1.items) {
|
|
2792
|
+
if (identity.isScalar(key2)) {
|
|
2793
|
+
if (seenKeys.includes(key2.value)) {
|
|
2794
|
+
onError(`Ordered maps must not include duplicate keys: ${key2.value}`);
|
|
2795
2795
|
} else {
|
|
2796
|
-
seenKeys.push(
|
|
2796
|
+
seenKeys.push(key2.value);
|
|
2797
2797
|
}
|
|
2798
2798
|
}
|
|
2799
2799
|
}
|
|
@@ -2978,14 +2978,14 @@ var require_set = __commonJS({
|
|
|
2978
2978
|
super(schema);
|
|
2979
2979
|
this.tag = _YAMLSet.tag;
|
|
2980
2980
|
}
|
|
2981
|
-
add(
|
|
2981
|
+
add(key2) {
|
|
2982
2982
|
let pair;
|
|
2983
|
-
if (identity.isPair(
|
|
2984
|
-
pair =
|
|
2985
|
-
else if (
|
|
2986
|
-
pair = new Pair.Pair(
|
|
2983
|
+
if (identity.isPair(key2))
|
|
2984
|
+
pair = key2;
|
|
2985
|
+
else if (key2 && typeof key2 === "object" && "key" in key2 && "value" in key2 && key2.value === null)
|
|
2986
|
+
pair = new Pair.Pair(key2.key, null);
|
|
2987
2987
|
else
|
|
2988
|
-
pair = new Pair.Pair(
|
|
2988
|
+
pair = new Pair.Pair(key2, null);
|
|
2989
2989
|
const prev = YAMLMap.findPair(this.items, pair.key);
|
|
2990
2990
|
if (!prev)
|
|
2991
2991
|
this.items.push(pair);
|
|
@@ -2994,18 +2994,18 @@ var require_set = __commonJS({
|
|
|
2994
2994
|
* If `keepPair` is `true`, returns the Pair matching `key`.
|
|
2995
2995
|
* Otherwise, returns the value of that Pair's key.
|
|
2996
2996
|
*/
|
|
2997
|
-
get(
|
|
2998
|
-
const pair = YAMLMap.findPair(this.items,
|
|
2997
|
+
get(key2, keepPair) {
|
|
2998
|
+
const pair = YAMLMap.findPair(this.items, key2);
|
|
2999
2999
|
return !keepPair && identity.isPair(pair) ? identity.isScalar(pair.key) ? pair.key.value : pair.key : pair;
|
|
3000
3000
|
}
|
|
3001
|
-
set(
|
|
3001
|
+
set(key2, value) {
|
|
3002
3002
|
if (typeof value !== "boolean")
|
|
3003
3003
|
throw new Error(`Expected boolean value for set(key, value) in a YAML set, not ${typeof value}`);
|
|
3004
|
-
const prev = YAMLMap.findPair(this.items,
|
|
3004
|
+
const prev = YAMLMap.findPair(this.items, key2);
|
|
3005
3005
|
if (prev && !value) {
|
|
3006
3006
|
this.items.splice(this.items.indexOf(prev), 1);
|
|
3007
3007
|
} else if (!prev && value) {
|
|
3008
|
-
this.items.push(new Pair.Pair(
|
|
3008
|
+
this.items.push(new Pair.Pair(key2));
|
|
3009
3009
|
}
|
|
3010
3010
|
}
|
|
3011
3011
|
toJSON(_, ctx) {
|
|
@@ -3252,7 +3252,7 @@ var require_tags = __commonJS({
|
|
|
3252
3252
|
if (Array.isArray(customTags))
|
|
3253
3253
|
tags = [];
|
|
3254
3254
|
else {
|
|
3255
|
-
const keys = Array.from(schemas.keys()).filter((
|
|
3255
|
+
const keys = Array.from(schemas.keys()).filter((key2) => key2 !== "yaml11").map((key2) => JSON.stringify(key2)).join(", ");
|
|
3256
3256
|
throw new Error(`Unknown schema "${schemaName}"; use one of ${keys} or define customTags array`);
|
|
3257
3257
|
}
|
|
3258
3258
|
}
|
|
@@ -3268,7 +3268,7 @@ var require_tags = __commonJS({
|
|
|
3268
3268
|
const tagObj = typeof tag === "string" ? tagsByName[tag] : tag;
|
|
3269
3269
|
if (!tagObj) {
|
|
3270
3270
|
const tagName = JSON.stringify(tag);
|
|
3271
|
-
const keys = Object.keys(tagsByName).map((
|
|
3271
|
+
const keys = Object.keys(tagsByName).map((key2) => JSON.stringify(key2)).join(", ");
|
|
3272
3272
|
throw new Error(`Unknown custom tag ${tagName}; use one of ${keys}`);
|
|
3273
3273
|
}
|
|
3274
3274
|
if (!tags2.includes(tagObj))
|
|
@@ -3484,11 +3484,11 @@ var require_Document = __commonJS({
|
|
|
3484
3484
|
* `name` will be used as a prefix for a new unique anchor.
|
|
3485
3485
|
* If `name` is undefined, the generated anchor will use 'a' as a prefix.
|
|
3486
3486
|
*/
|
|
3487
|
-
createAlias(node,
|
|
3487
|
+
createAlias(node, name2) {
|
|
3488
3488
|
if (!node.anchor) {
|
|
3489
3489
|
const prev = anchors.anchorNames(this);
|
|
3490
3490
|
node.anchor = // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
|
|
3491
|
-
!
|
|
3491
|
+
!name2 || prev.has(name2) ? anchors.findNewAnchor(name2 || "a", prev) : name2;
|
|
3492
3492
|
}
|
|
3493
3493
|
return new Alias.Alias(node.anchor);
|
|
3494
3494
|
}
|
|
@@ -3532,8 +3532,8 @@ var require_Document = __commonJS({
|
|
|
3532
3532
|
* Convert a key and a value into a `Pair` using the current schema,
|
|
3533
3533
|
* recursively wrapping all values as `Scalar` or `Collection` nodes.
|
|
3534
3534
|
*/
|
|
3535
|
-
createPair(
|
|
3536
|
-
const k = this.createNode(
|
|
3535
|
+
createPair(key2, value, options = {}) {
|
|
3536
|
+
const k = this.createNode(key2, null, options);
|
|
3537
3537
|
const v = this.createNode(value, null, options);
|
|
3538
3538
|
return new Pair.Pair(k, v);
|
|
3539
3539
|
}
|
|
@@ -3541,8 +3541,8 @@ var require_Document = __commonJS({
|
|
|
3541
3541
|
* Removes a value from the document.
|
|
3542
3542
|
* @returns `true` if the item was found and removed.
|
|
3543
3543
|
*/
|
|
3544
|
-
delete(
|
|
3545
|
-
return assertCollection(this.contents) ? this.contents.delete(
|
|
3544
|
+
delete(key2) {
|
|
3545
|
+
return assertCollection(this.contents) ? this.contents.delete(key2) : false;
|
|
3546
3546
|
}
|
|
3547
3547
|
/**
|
|
3548
3548
|
* Removes a value from the document.
|
|
@@ -3562,8 +3562,8 @@ var require_Document = __commonJS({
|
|
|
3562
3562
|
* scalar values from their surrounding node; to disable set `keepScalar` to
|
|
3563
3563
|
* `true` (collections are always returned intact).
|
|
3564
3564
|
*/
|
|
3565
|
-
get(
|
|
3566
|
-
return identity.isCollection(this.contents) ? this.contents.get(
|
|
3565
|
+
get(key2, keepScalar) {
|
|
3566
|
+
return identity.isCollection(this.contents) ? this.contents.get(key2, keepScalar) : void 0;
|
|
3567
3567
|
}
|
|
3568
3568
|
/**
|
|
3569
3569
|
* Returns item at `path`, or `undefined` if not found. By default unwraps
|
|
@@ -3578,8 +3578,8 @@ var require_Document = __commonJS({
|
|
|
3578
3578
|
/**
|
|
3579
3579
|
* Checks if the document includes a value with the key `key`.
|
|
3580
3580
|
*/
|
|
3581
|
-
has(
|
|
3582
|
-
return identity.isCollection(this.contents) ? this.contents.has(
|
|
3581
|
+
has(key2) {
|
|
3582
|
+
return identity.isCollection(this.contents) ? this.contents.has(key2) : false;
|
|
3583
3583
|
}
|
|
3584
3584
|
/**
|
|
3585
3585
|
* Checks if the document includes a value at `path`.
|
|
@@ -3593,11 +3593,11 @@ var require_Document = __commonJS({
|
|
|
3593
3593
|
* Sets a value in this document. For `!!set`, `value` needs to be a
|
|
3594
3594
|
* boolean to add/remove the item from the set.
|
|
3595
3595
|
*/
|
|
3596
|
-
set(
|
|
3596
|
+
set(key2, value) {
|
|
3597
3597
|
if (this.contents == null) {
|
|
3598
|
-
this.contents = Collection.collectionFromPath(this.schema, [
|
|
3598
|
+
this.contents = Collection.collectionFromPath(this.schema, [key2], value);
|
|
3599
3599
|
} else if (assertCollection(this.contents)) {
|
|
3600
|
-
this.contents.set(
|
|
3600
|
+
this.contents.set(key2, value);
|
|
3601
3601
|
}
|
|
3602
3602
|
}
|
|
3603
3603
|
/**
|
|
@@ -3707,9 +3707,9 @@ var require_errors = __commonJS({
|
|
|
3707
3707
|
"node_modules/.pnpm/yaml@2.9.1/node_modules/yaml/dist/errors.js"(exports) {
|
|
3708
3708
|
"use strict";
|
|
3709
3709
|
var YAMLError = class extends Error {
|
|
3710
|
-
constructor(
|
|
3710
|
+
constructor(name2, pos, code, message2) {
|
|
3711
3711
|
super();
|
|
3712
|
-
this.name =
|
|
3712
|
+
this.name = name2;
|
|
3713
3713
|
this.code = code;
|
|
3714
3714
|
this.message = message2;
|
|
3715
3715
|
this.pos = pos;
|
|
@@ -3905,24 +3905,24 @@ var require_resolve_props = __commonJS({
|
|
|
3905
3905
|
var require_util_contains_newline = __commonJS({
|
|
3906
3906
|
"node_modules/.pnpm/yaml@2.9.1/node_modules/yaml/dist/compose/util-contains-newline.js"(exports) {
|
|
3907
3907
|
"use strict";
|
|
3908
|
-
function containsNewline(
|
|
3909
|
-
if (!
|
|
3908
|
+
function containsNewline(key2) {
|
|
3909
|
+
if (!key2)
|
|
3910
3910
|
return null;
|
|
3911
|
-
switch (
|
|
3911
|
+
switch (key2.type) {
|
|
3912
3912
|
case "alias":
|
|
3913
3913
|
case "scalar":
|
|
3914
3914
|
case "double-quoted-scalar":
|
|
3915
3915
|
case "single-quoted-scalar":
|
|
3916
|
-
if (
|
|
3916
|
+
if (key2.source.includes("\n"))
|
|
3917
3917
|
return true;
|
|
3918
|
-
if (
|
|
3919
|
-
for (const st of
|
|
3918
|
+
if (key2.end) {
|
|
3919
|
+
for (const st of key2.end)
|
|
3920
3920
|
if (st.type === "newline")
|
|
3921
3921
|
return true;
|
|
3922
3922
|
}
|
|
3923
3923
|
return false;
|
|
3924
3924
|
case "flow-collection":
|
|
3925
|
-
for (const it of
|
|
3925
|
+
for (const it of key2.items) {
|
|
3926
3926
|
for (const st of it.start)
|
|
3927
3927
|
if (st.type === "newline")
|
|
3928
3928
|
return true;
|
|
@@ -3996,10 +3996,10 @@ var require_resolve_block_map = __commonJS({
|
|
|
3996
3996
|
let offset = bm.offset;
|
|
3997
3997
|
let commentEnd = null;
|
|
3998
3998
|
for (const collItem of bm.items) {
|
|
3999
|
-
const { start, key, sep: sep2, value } = collItem;
|
|
3999
|
+
const { start, key: key2, sep: sep2, value } = collItem;
|
|
4000
4000
|
const keyProps = resolveProps.resolveProps(start, {
|
|
4001
4001
|
indicator: "explicit-key-ind",
|
|
4002
|
-
next:
|
|
4002
|
+
next: key2 ?? sep2?.[0],
|
|
4003
4003
|
offset,
|
|
4004
4004
|
onError,
|
|
4005
4005
|
parentIndent: bm.indent,
|
|
@@ -4007,10 +4007,10 @@ var require_resolve_block_map = __commonJS({
|
|
|
4007
4007
|
});
|
|
4008
4008
|
const implicitKey = !keyProps.found;
|
|
4009
4009
|
if (implicitKey) {
|
|
4010
|
-
if (
|
|
4011
|
-
if (
|
|
4010
|
+
if (key2) {
|
|
4011
|
+
if (key2.type === "block-seq")
|
|
4012
4012
|
onError(offset, "BLOCK_AS_IMPLICIT_KEY", "A block sequence may not be used as an implicit map key");
|
|
4013
|
-
else if ("indent" in
|
|
4013
|
+
else if ("indent" in key2 && key2.indent !== bm.indent)
|
|
4014
4014
|
onError(offset, "BAD_INDENT", startColMsg);
|
|
4015
4015
|
}
|
|
4016
4016
|
if (!keyProps.anchor && !keyProps.tag && !sep2) {
|
|
@@ -4023,17 +4023,17 @@ var require_resolve_block_map = __commonJS({
|
|
|
4023
4023
|
}
|
|
4024
4024
|
continue;
|
|
4025
4025
|
}
|
|
4026
|
-
if (keyProps.newlineAfterProp || utilContainsNewline.containsNewline(
|
|
4027
|
-
onError(
|
|
4026
|
+
if (keyProps.newlineAfterProp || utilContainsNewline.containsNewline(key2)) {
|
|
4027
|
+
onError(key2 ?? start[start.length - 1], "MULTILINE_IMPLICIT_KEY", "Implicit keys need to be on a single line");
|
|
4028
4028
|
}
|
|
4029
4029
|
} else if (keyProps.found?.indent !== bm.indent) {
|
|
4030
4030
|
onError(offset, "BAD_INDENT", startColMsg);
|
|
4031
4031
|
}
|
|
4032
4032
|
ctx.atKey = true;
|
|
4033
4033
|
const keyStart = keyProps.end;
|
|
4034
|
-
const keyNode =
|
|
4034
|
+
const keyNode = key2 ? composeNode(ctx, key2, keyProps, onError) : composeEmptyNode(ctx, keyStart, start, null, keyProps, onError);
|
|
4035
4035
|
if (ctx.schema.compat)
|
|
4036
|
-
utilFlowIndentCheck.flowIndentCheck(bm.indent,
|
|
4036
|
+
utilFlowIndentCheck.flowIndentCheck(bm.indent, key2, onError);
|
|
4037
4037
|
ctx.atKey = false;
|
|
4038
4038
|
if (utilMapIncludes.mapIncludes(ctx, map.items, keyNode))
|
|
4039
4039
|
onError(keyStart, "DUPLICATE_KEY", "Map keys must be unique");
|
|
@@ -4043,7 +4043,7 @@ var require_resolve_block_map = __commonJS({
|
|
|
4043
4043
|
offset: keyNode.range[2],
|
|
4044
4044
|
onError,
|
|
4045
4045
|
parentIndent: bm.indent,
|
|
4046
|
-
startOnNewline: !
|
|
4046
|
+
startOnNewline: !key2 || key2.type === "block-scalar"
|
|
4047
4047
|
});
|
|
4048
4048
|
offset = valueProps.end;
|
|
4049
4049
|
if (valueProps.found) {
|
|
@@ -4207,11 +4207,11 @@ var require_resolve_flow_collection = __commonJS({
|
|
|
4207
4207
|
let offset = fc.offset + fc.start.source.length;
|
|
4208
4208
|
for (let i = 0; i < fc.items.length; ++i) {
|
|
4209
4209
|
const collItem = fc.items[i];
|
|
4210
|
-
const { start, key, sep: sep2, value } = collItem;
|
|
4210
|
+
const { start, key: key2, sep: sep2, value } = collItem;
|
|
4211
4211
|
const props = resolveProps.resolveProps(start, {
|
|
4212
4212
|
flow: fcName,
|
|
4213
4213
|
indicator: "explicit-key-ind",
|
|
4214
|
-
next:
|
|
4214
|
+
next: key2 ?? sep2?.[0],
|
|
4215
4215
|
offset,
|
|
4216
4216
|
onError,
|
|
4217
4217
|
parentIndent: fc.indent,
|
|
@@ -4232,9 +4232,9 @@ var require_resolve_flow_collection = __commonJS({
|
|
|
4232
4232
|
offset = props.end;
|
|
4233
4233
|
continue;
|
|
4234
4234
|
}
|
|
4235
|
-
if (!isMap && ctx.options.strict && utilContainsNewline.containsNewline(
|
|
4235
|
+
if (!isMap && ctx.options.strict && utilContainsNewline.containsNewline(key2))
|
|
4236
4236
|
onError(
|
|
4237
|
-
|
|
4237
|
+
key2,
|
|
4238
4238
|
// checked by containsNewline()
|
|
4239
4239
|
"MULTILINE_IMPLICIT_KEY",
|
|
4240
4240
|
"Implicit keys of flow sequence pairs need to be on a single line"
|
|
@@ -4281,8 +4281,8 @@ var require_resolve_flow_collection = __commonJS({
|
|
|
4281
4281
|
} else {
|
|
4282
4282
|
ctx.atKey = true;
|
|
4283
4283
|
const keyStart = props.end;
|
|
4284
|
-
const keyNode =
|
|
4285
|
-
if (isBlock(
|
|
4284
|
+
const keyNode = key2 ? composeNode(ctx, key2, props, onError) : composeEmptyNode(ctx, keyStart, start, null, props, onError);
|
|
4285
|
+
if (isBlock(key2))
|
|
4286
4286
|
onError(keyNode.range, "BLOCK_IN_FLOW", blockMsg);
|
|
4287
4287
|
ctx.atKey = false;
|
|
4288
4288
|
const valueProps = resolveProps.resolveProps(sep2 ?? [], {
|
|
@@ -4349,8 +4349,8 @@ var require_resolve_flow_collection = __commonJS({
|
|
|
4349
4349
|
if (ce?.source === expectedEnd)
|
|
4350
4350
|
cePos = ce.offset + ce.source.length;
|
|
4351
4351
|
else {
|
|
4352
|
-
const
|
|
4353
|
-
const msg = atRoot ? `${
|
|
4352
|
+
const name2 = fcName[0].toUpperCase() + fcName.substring(1);
|
|
4353
|
+
const msg = atRoot ? `${name2} must end with a ${expectedEnd}` : `${name2} in block collection must be sufficiently indented and end with a ${expectedEnd}`;
|
|
4354
4354
|
onError(offset, atRoot ? "MISSING_CHAR" : "BAD_INDENT", msg);
|
|
4355
4355
|
if (ce && ce.source.length !== 1)
|
|
4356
4356
|
ee.unshift(ce);
|
|
@@ -5432,9 +5432,9 @@ var require_cst_scalar = __commonJS({
|
|
|
5432
5432
|
];
|
|
5433
5433
|
if (!addEndtoBlockProps(props, "end" in token ? token.end : void 0))
|
|
5434
5434
|
props.push({ type: "newline", offset: -1, indent, source: "\n" });
|
|
5435
|
-
for (const
|
|
5436
|
-
if (
|
|
5437
|
-
delete token[
|
|
5435
|
+
for (const key2 of Object.keys(token))
|
|
5436
|
+
if (key2 !== "type" && key2 !== "offset")
|
|
5437
|
+
delete token[key2];
|
|
5438
5438
|
Object.assign(token, { type: "block-scalar", indent, props, source: body });
|
|
5439
5439
|
}
|
|
5440
5440
|
}
|
|
@@ -5482,9 +5482,9 @@ var require_cst_scalar = __commonJS({
|
|
|
5482
5482
|
default: {
|
|
5483
5483
|
const indent = "indent" in token ? token.indent : -1;
|
|
5484
5484
|
const end = "end" in token && Array.isArray(token.end) ? token.end.filter((st) => st.type === "space" || st.type === "comment" || st.type === "newline") : [];
|
|
5485
|
-
for (const
|
|
5486
|
-
if (
|
|
5487
|
-
delete token[
|
|
5485
|
+
for (const key2 of Object.keys(token))
|
|
5486
|
+
if (key2 !== "type" && key2 !== "offset")
|
|
5487
|
+
delete token[key2];
|
|
5488
5488
|
Object.assign(token, { type, indent, source, end });
|
|
5489
5489
|
}
|
|
5490
5490
|
}
|
|
@@ -5539,12 +5539,12 @@ var require_cst_stringify = __commonJS({
|
|
|
5539
5539
|
}
|
|
5540
5540
|
}
|
|
5541
5541
|
}
|
|
5542
|
-
function stringifyItem({ start, key, sep: sep2, value }) {
|
|
5542
|
+
function stringifyItem({ start, key: key2, sep: sep2, value }) {
|
|
5543
5543
|
let res = "";
|
|
5544
5544
|
for (const st of start)
|
|
5545
5545
|
res += st.source;
|
|
5546
|
-
if (
|
|
5547
|
-
res += stringifyToken(
|
|
5546
|
+
if (key2)
|
|
5547
|
+
res += stringifyToken(key2);
|
|
5548
5548
|
if (sep2)
|
|
5549
5549
|
for (const st of sep2)
|
|
5550
5550
|
res += st.source;
|
|
@@ -6876,7 +6876,7 @@ var require_parser = __commonJS({
|
|
|
6876
6876
|
});
|
|
6877
6877
|
} else if (isFlowToken(it.key) && !includesToken(it.sep, "newline")) {
|
|
6878
6878
|
const start2 = getFirstKeyStartProps(it.start);
|
|
6879
|
-
const
|
|
6879
|
+
const key2 = it.key;
|
|
6880
6880
|
const sep2 = it.sep;
|
|
6881
6881
|
sep2.push(this.sourceToken);
|
|
6882
6882
|
delete it.key;
|
|
@@ -6885,7 +6885,7 @@ var require_parser = __commonJS({
|
|
|
6885
6885
|
type: "block-map",
|
|
6886
6886
|
offset: this.offset,
|
|
6887
6887
|
indent: this.indent,
|
|
6888
|
-
items: [{ start: start2, key, sep: sep2 }]
|
|
6888
|
+
items: [{ start: start2, key: key2, sep: sep2 }]
|
|
6889
6889
|
});
|
|
6890
6890
|
} else if (start.length > 0) {
|
|
6891
6891
|
it.sep = it.sep.concat(start, this.sourceToken);
|
|
@@ -7396,9 +7396,9 @@ function runMenu(input, output, head, rows, onKey) {
|
|
|
7396
7396
|
let headLines = 0;
|
|
7397
7397
|
let drawn = 0;
|
|
7398
7398
|
const frame = () => {
|
|
7399
|
-
const
|
|
7400
|
-
const lines = [...rows(), ...fitHint(hint,
|
|
7401
|
-
drawn = lines.reduce((n, line) => n + screenLines(line,
|
|
7399
|
+
const cols2 = width();
|
|
7400
|
+
const lines = [...rows(), ...fitHint(hint, cols2)];
|
|
7401
|
+
drawn = lines.reduce((n, line) => n + screenLines(line, cols2), 0);
|
|
7402
7402
|
return lines.map((line) => `${CLEAR_LINE}\r${line}
|
|
7403
7403
|
`).join("");
|
|
7404
7404
|
};
|
|
@@ -7426,12 +7426,12 @@ ${SHOW_CURSOR}`);
|
|
|
7426
7426
|
reject(outcome.error);
|
|
7427
7427
|
}
|
|
7428
7428
|
};
|
|
7429
|
-
const onKeypress = (text3,
|
|
7430
|
-
const
|
|
7431
|
-
if (
|
|
7429
|
+
const onKeypress = (text3, key2) => {
|
|
7430
|
+
const name2 = key2?.name ?? text3;
|
|
7431
|
+
if (key2?.ctrl && (name2 === "c" || name2 === "d") || name2 === "escape" || name2 === "q" && !key2?.ctrl) {
|
|
7432
7432
|
return finish({ error: new PromptCancelled() });
|
|
7433
7433
|
}
|
|
7434
|
-
const result = onKey(text3,
|
|
7434
|
+
const result = onKey(text3, name2);
|
|
7435
7435
|
if (result === "redraw") output.write(`\r${up(drawn)}${CLEAR_DOWN}${frame()}`);
|
|
7436
7436
|
else if (result) finish(result);
|
|
7437
7437
|
};
|
|
@@ -7440,9 +7440,9 @@ ${SHOW_CURSOR}`);
|
|
|
7440
7440
|
try {
|
|
7441
7441
|
emitKeypressEvents(input);
|
|
7442
7442
|
input.setRawMode?.(true);
|
|
7443
|
-
const
|
|
7444
|
-
const top = [question, ...note ? note.split("\n").flatMap((line) => wrapWords(line,
|
|
7445
|
-
headLines = top.reduce((n, line) => n + screenLines(line,
|
|
7443
|
+
const cols2 = width();
|
|
7444
|
+
const top = [question, ...note ? note.split("\n").flatMap((line) => wrapWords(line, cols2)) : []];
|
|
7445
|
+
headLines = top.reduce((n, line) => n + screenLines(line, cols2), 0);
|
|
7446
7446
|
output.write(`${HIDE_CURSOR}${top.map((line) => `${line}
|
|
7447
7447
|
`).join("")}${frame()}`);
|
|
7448
7448
|
input.on("keypress", onKeypress);
|
|
@@ -7477,9 +7477,9 @@ function wrapWords(text3, columns) {
|
|
|
7477
7477
|
function marker(options) {
|
|
7478
7478
|
return options.color ? options.trueColor ? "\x1B[1;38;2;253;75;3m" : "\x1B[1;38;5;202m" : "\x1B[1m";
|
|
7479
7479
|
}
|
|
7480
|
-
function move(current, count2, text3,
|
|
7481
|
-
if (
|
|
7482
|
-
if (
|
|
7480
|
+
function move(current, count2, text3, name2) {
|
|
7481
|
+
if (name2 === "up" || name2 === "k") return (current - 1 + count2) % count2;
|
|
7482
|
+
if (name2 === "down" || name2 === "j") return (current + 1) % count2;
|
|
7483
7483
|
if (text3 && /^[1-9]$/.test(text3) && Number(text3) <= count2) return Number(text3) - 1;
|
|
7484
7484
|
return null;
|
|
7485
7485
|
}
|
|
@@ -7487,9 +7487,9 @@ function selectMenu(input, output, question, choices, options = {}) {
|
|
|
7487
7487
|
let current = Math.min(Math.max(options.initial ?? 0, 0), choices.length - 1);
|
|
7488
7488
|
const on = marker(options);
|
|
7489
7489
|
const rows = () => choices.map((c, i) => i === current ? `${on}> ${c}${OFF}` : ` ${c}`);
|
|
7490
|
-
return runMenu(input, output, { question, hint: HINT, columns: options.columns }, rows, (text3,
|
|
7491
|
-
if (
|
|
7492
|
-
const next = move(current, choices.length, text3,
|
|
7490
|
+
return runMenu(input, output, { question, hint: HINT, columns: options.columns }, rows, (text3, name2) => {
|
|
7491
|
+
if (name2 === "return" || name2 === "enter") return { pick: current, summary: choices[current] ?? "" };
|
|
7492
|
+
const next = move(current, choices.length, text3, name2);
|
|
7493
7493
|
if (next === null || next === current) return null;
|
|
7494
7494
|
current = next;
|
|
7495
7495
|
return "redraw";
|
|
@@ -7503,22 +7503,22 @@ function multiSelectMenu(input, output, question, choices, options = {}) {
|
|
|
7503
7503
|
const pad2 = Math.max(...choices.map((c) => c.length));
|
|
7504
7504
|
const label = (i) => {
|
|
7505
7505
|
const tag = options.tags?.[i];
|
|
7506
|
-
const
|
|
7507
|
-
if (!tag) return
|
|
7508
|
-
const
|
|
7506
|
+
const name2 = choices[i] ?? "";
|
|
7507
|
+
if (!tag) return name2;
|
|
7508
|
+
const cols2 = options.columns?.() ?? Infinity;
|
|
7509
7509
|
const grey = options.color ? `${GREY}${tag}${GREY_OFF}` : tag;
|
|
7510
|
-
if (6 + pad2 + 3 + tag.length <=
|
|
7511
|
-
if (6 +
|
|
7512
|
-
return
|
|
7510
|
+
if (6 + pad2 + 3 + tag.length <= cols2) return `${name2.padEnd(pad2)} ${grey}`;
|
|
7511
|
+
if (6 + name2.length + 1 + tag.length <= cols2) return `${name2} ${grey}`;
|
|
7512
|
+
return name2;
|
|
7513
7513
|
};
|
|
7514
7514
|
const rows = () => choices.map((_, i) => `${i === current ? pointer : " "} [${ticked[i] ? "x" : " "}] ${label(i)}`);
|
|
7515
7515
|
const head = { question, note: options.note, hint: options.hint ?? MULTI_HINT, columns: options.columns };
|
|
7516
|
-
return runMenu(input, output, head, rows, (text3,
|
|
7517
|
-
if (
|
|
7516
|
+
return runMenu(input, output, head, rows, (text3, name2) => {
|
|
7517
|
+
if (name2 === "return" || name2 === "enter") {
|
|
7518
7518
|
const picks = choices.flatMap((_, i) => ticked[i] ? [i] : []);
|
|
7519
7519
|
return { pick: picks, summary: picks.map((i) => choices[i]).join(", ") || "none" };
|
|
7520
7520
|
}
|
|
7521
|
-
if (
|
|
7521
|
+
if (name2 === "space") {
|
|
7522
7522
|
ticked[current] = !ticked[current];
|
|
7523
7523
|
return "redraw";
|
|
7524
7524
|
}
|
|
@@ -7527,7 +7527,7 @@ function multiSelectMenu(input, output, question, choices, options = {}) {
|
|
|
7527
7527
|
ticked[current] = !ticked[current];
|
|
7528
7528
|
return "redraw";
|
|
7529
7529
|
}
|
|
7530
|
-
const next = move(current, choices.length, text3,
|
|
7530
|
+
const next = move(current, choices.length, text3, name2);
|
|
7531
7531
|
if (next === null || next === current) return null;
|
|
7532
7532
|
current = next;
|
|
7533
7533
|
return "redraw";
|
|
@@ -7553,9 +7553,9 @@ function listenForEnter(input, onEnter, onCancel) {
|
|
|
7553
7553
|
stop();
|
|
7554
7554
|
onCancel();
|
|
7555
7555
|
};
|
|
7556
|
-
const onKeypress = (_text,
|
|
7557
|
-
if (
|
|
7558
|
-
else if (
|
|
7556
|
+
const onKeypress = (_text, key2) => {
|
|
7557
|
+
if (key2?.ctrl && key2.name === "c") cancel();
|
|
7558
|
+
else if (key2?.name === "return" || key2?.name === "enter") onEnter();
|
|
7559
7559
|
};
|
|
7560
7560
|
try {
|
|
7561
7561
|
emitKeypressEvents(input);
|
|
@@ -7593,10 +7593,10 @@ function readPaste(input, output, question) {
|
|
|
7593
7593
|
else reject(outcome.error);
|
|
7594
7594
|
};
|
|
7595
7595
|
const done = () => finish({ text: lines.join("\n").trim() });
|
|
7596
|
-
const onKeypress = (_text,
|
|
7597
|
-
if (
|
|
7598
|
-
else if (
|
|
7599
|
-
else if (settle &&
|
|
7596
|
+
const onKeypress = (_text, key2) => {
|
|
7597
|
+
if (key2?.name === "paste-start") pasting = true;
|
|
7598
|
+
else if (key2?.name === "paste-end") pasting = false;
|
|
7599
|
+
else if (settle && key2?.name !== "return" && key2?.name !== "enter") {
|
|
7600
7600
|
clearTimeout(settle);
|
|
7601
7601
|
settle = void 0;
|
|
7602
7602
|
}
|
|
@@ -7868,7 +7868,8 @@ var COMMAND_OPTIONS = {
|
|
|
7868
7868
|
list: { type: "string" },
|
|
7869
7869
|
batch: { type: "string" },
|
|
7870
7870
|
"no-wait": { type: "boolean" },
|
|
7871
|
-
force: { type: "boolean" }
|
|
7871
|
+
force: { type: "boolean" },
|
|
7872
|
+
for: { type: "string" }
|
|
7872
7873
|
},
|
|
7873
7874
|
search: { research: { type: "boolean" }, limit: { type: "string" } },
|
|
7874
7875
|
connections: { all: { type: "boolean" } },
|
|
@@ -7946,7 +7947,7 @@ function parseCommandLine(argv) {
|
|
|
7946
7947
|
return { command: null, args: [], flags: strictParse(argv, { ...GLOBAL_OPTIONS, ...SETUP_OPTIONS }).values };
|
|
7947
7948
|
}
|
|
7948
7949
|
let words = 1;
|
|
7949
|
-
let
|
|
7950
|
+
let name2 = first2;
|
|
7950
7951
|
if (TWO_WORD.has(first2)) {
|
|
7951
7952
|
const second = positionals[1];
|
|
7952
7953
|
if (first2 === "skills" && second !== "add") {
|
|
@@ -7957,14 +7958,14 @@ function parseCommandLine(argv) {
|
|
|
7957
7958
|
);
|
|
7958
7959
|
}
|
|
7959
7960
|
if (second === void 0) throw usageError(`\`amdahl ${first2}\` needs a subcommand.`);
|
|
7960
|
-
|
|
7961
|
+
name2 = `${first2} ${second}`;
|
|
7961
7962
|
words = 2;
|
|
7962
7963
|
}
|
|
7963
|
-
|
|
7964
|
-
const spec = COMMAND_OPTIONS[
|
|
7964
|
+
name2 = ALIASES[name2] ?? name2;
|
|
7965
|
+
const spec = COMMAND_OPTIONS[name2];
|
|
7965
7966
|
if (!spec) throw usageError(`Unknown command \`${positionals.slice(0, words).join(" ")}\`.`, `Run \`${amdahlCommand("--help")}\` to see the commands.`);
|
|
7966
7967
|
const strict = strictParse(argv, { ...GLOBAL_OPTIONS, ...spec });
|
|
7967
|
-
return { command:
|
|
7968
|
+
return { command: name2, args: strict.positionals.slice(words), flags: strict.values };
|
|
7968
7969
|
}
|
|
7969
7970
|
function strictParse(argv, options) {
|
|
7970
7971
|
try {
|
|
@@ -8006,6 +8007,10 @@ What you can do:
|
|
|
8006
8007
|
amdahl optimize --list drafts.csv
|
|
8007
8008
|
Rewrite a whole list in one batch; results go
|
|
8008
8009
|
to drafts.optimized.csv
|
|
8010
|
+
amdahl optimize --list drafts.csv --for lemlist
|
|
8011
|
+
Also write drafts-lemlist.csv, a file your
|
|
8012
|
+
sequencer imports, and say how (Instantly,
|
|
8013
|
+
Smartlead, lemlist, HeyReach, Apollo and more)
|
|
8009
8014
|
amdahl search "<question>" Ask about your customers, calls and deals
|
|
8010
8015
|
amdahl connect hubspot Add a CRM or call recorder in the console
|
|
8011
8016
|
(amdahl connections lists what is connected)
|
|
@@ -8032,13 +8037,20 @@ Commands:
|
|
|
8032
8037
|
--json prints {ok, file, result}: the message is .result.message
|
|
8033
8038
|
and the run id is .result.run_id.
|
|
8034
8039
|
optimize --list <file.csv|file.jsonl> [--no-wait] [--batch <id>] [--force]
|
|
8035
|
-
[the optimize flags above, for every message]
|
|
8040
|
+
[--for <tool>] [the optimize flags above, for every message]
|
|
8036
8041
|
A CSV needs a message column, and may have item_id, channel,
|
|
8037
8042
|
evidence, on_unsupported, facts and rules. Any other column is
|
|
8038
8043
|
copied to the results as it is. --batch <id> picks up a batch
|
|
8039
8044
|
queued earlier, with the same list. --force replaces an existing
|
|
8040
8045
|
results file. In the results CSV, a cell that starts with =, +, -
|
|
8041
8046
|
or @ (a phone number, say) gets a ' in front: it is no formula.
|
|
8047
|
+
--for <tool> a CSV list only: also write the messages Amdahl wrote
|
|
8048
|
+
as a CSV that tool imports (<list>-<tool>.csv), and say
|
|
8049
|
+
how to import it. Tools: instantly, smartlead, lemlist,
|
|
8050
|
+
heyreach, reply_io, apollo, outreach, salesloft,
|
|
8051
|
+
hubspot, lgm, woodpecker, other (any tool that imports
|
|
8052
|
+
a CSV). lemlist, reply_io and other take both channels,
|
|
8053
|
+
so add --channel email|linkedin.
|
|
8042
8054
|
search "<question>" [--research] [--limit <n>]
|
|
8043
8055
|
--research ask for a research job: a deeper, cited answer (needs
|
|
8044
8056
|
a Customer agent key, amdahl keys create --preset
|
|
@@ -8104,7 +8116,7 @@ Global options:
|
|
|
8104
8116
|
`;
|
|
8105
8117
|
|
|
8106
8118
|
// src/version.ts
|
|
8107
|
-
var VERSION = "0.4.
|
|
8119
|
+
var VERSION = "0.4.2";
|
|
8108
8120
|
|
|
8109
8121
|
// src/api.ts
|
|
8110
8122
|
var CLIENT_HEADER = {
|
|
@@ -8180,20 +8192,20 @@ function parseErrorBody(errorBody, statusCode) {
|
|
|
8180
8192
|
}
|
|
8181
8193
|
var PLATFORM = "/api/platform/v1";
|
|
8182
8194
|
var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
8183
|
-
function assertUuid(
|
|
8195
|
+
function assertUuid(name2, value) {
|
|
8184
8196
|
if (typeof value !== "string" || value.length === 0) {
|
|
8185
8197
|
throw new Error(
|
|
8186
|
-
`mcpKeys client: ${
|
|
8198
|
+
`mcpKeys client: ${name2} must be a non-empty string (got ${typeof value === "string" ? "empty string" : String(value)})`
|
|
8187
8199
|
);
|
|
8188
8200
|
}
|
|
8189
8201
|
const lowered = value.toLowerCase();
|
|
8190
8202
|
if (lowered === "undefined" || lowered === "null") {
|
|
8191
8203
|
throw new Error(
|
|
8192
|
-
`mcpKeys client: ${
|
|
8204
|
+
`mcpKeys client: ${name2} is the literal string '${value}'. Fix the caller rather than relaxing this guard.`
|
|
8193
8205
|
);
|
|
8194
8206
|
}
|
|
8195
8207
|
if (!UUID_RE.test(value)) {
|
|
8196
|
-
throw new Error(`mcpKeys client: ${
|
|
8208
|
+
throw new Error(`mcpKeys client: ${name2} must be a UUID (got '${value}')`);
|
|
8197
8209
|
}
|
|
8198
8210
|
}
|
|
8199
8211
|
function createAmdahlClient(config) {
|
|
@@ -9014,9 +9026,9 @@ async function browserSignIn(ctx) {
|
|
|
9014
9026
|
const client = apiClient(ctx, { source: "profile", token: secrets.access_token });
|
|
9015
9027
|
const me = await call(() => client.cli.whoami());
|
|
9016
9028
|
const ws = me.workspace ?? { id: me.business_id, name: me.business_id, slug: me.business_id };
|
|
9017
|
-
const
|
|
9018
|
-
await ctx.secrets().set(keychainAccount(ctx.apiUrl,
|
|
9019
|
-
ctx.config.profiles[
|
|
9029
|
+
const name2 = explicitProfile ?? (PROFILE_NAME.test(ws.slug) ? ws.slug : "default");
|
|
9030
|
+
await ctx.secrets().set(keychainAccount(ctx.apiUrl, name2), secrets);
|
|
9031
|
+
ctx.config.profiles[name2] = {
|
|
9020
9032
|
api_url: ctx.apiUrl,
|
|
9021
9033
|
user_id: me.user_id,
|
|
9022
9034
|
email: me.email ?? null,
|
|
@@ -9024,11 +9036,11 @@ async function browserSignIn(ctx) {
|
|
|
9024
9036
|
scopes: me.scopes,
|
|
9025
9037
|
created_at: new Date(io.now()).toISOString()
|
|
9026
9038
|
};
|
|
9027
|
-
ctx.config.default_profile =
|
|
9039
|
+
ctx.config.default_profile = name2;
|
|
9028
9040
|
ctx.saveConfig();
|
|
9029
|
-
ctx.profileName =
|
|
9030
|
-
ctx.profile = ctx.config.profiles[
|
|
9031
|
-
return { profile:
|
|
9041
|
+
ctx.profileName = name2;
|
|
9042
|
+
ctx.profile = ctx.config.profiles[name2] ?? null;
|
|
9043
|
+
return { profile: name2, me, workspace: ws };
|
|
9032
9044
|
} finally {
|
|
9033
9045
|
stopKeys();
|
|
9034
9046
|
loopback.close();
|
|
@@ -9067,10 +9079,10 @@ async function logout(ctx) {
|
|
|
9067
9079
|
}
|
|
9068
9080
|
const notRevoked = [];
|
|
9069
9081
|
const store = ctx.secrets();
|
|
9070
|
-
for (const
|
|
9071
|
-
const profile = config.profiles[
|
|
9082
|
+
for (const name2 of names) {
|
|
9083
|
+
const profile = config.profiles[name2];
|
|
9072
9084
|
if (!profile) continue;
|
|
9073
|
-
const account = keychainAccount(profile.api_url,
|
|
9085
|
+
const account = keychainAccount(profile.api_url, name2);
|
|
9074
9086
|
const secrets = await store.get(account);
|
|
9075
9087
|
if (secrets) {
|
|
9076
9088
|
let ok = false;
|
|
@@ -9082,10 +9094,10 @@ async function logout(ctx) {
|
|
|
9082
9094
|
} catch {
|
|
9083
9095
|
ok = false;
|
|
9084
9096
|
}
|
|
9085
|
-
if (!ok) notRevoked.push(
|
|
9097
|
+
if (!ok) notRevoked.push(name2);
|
|
9086
9098
|
}
|
|
9087
9099
|
await store.delete(account);
|
|
9088
|
-
delete config.profiles[
|
|
9100
|
+
delete config.profiles[name2];
|
|
9089
9101
|
}
|
|
9090
9102
|
if (config.default_profile && !config.profiles[config.default_profile]) {
|
|
9091
9103
|
config.default_profile = Object.keys(config.profiles)[0] ?? null;
|
|
@@ -9143,7 +9155,7 @@ async function authToken(ctx) {
|
|
|
9143
9155
|
// src/ci.ts
|
|
9144
9156
|
var isSet = (value) => Boolean(value) && value !== "false" && value !== "0";
|
|
9145
9157
|
function ciVariable(env) {
|
|
9146
|
-
const named = ["CI", "JENKINS_URL", "TF_BUILD", "CODEBUILD_BUILD_ID", "TEAMCITY_VERSION", "GITHUB_ACTIONS", "GITLAB_CI", "BUILDKITE", "CIRCLECI"].find((
|
|
9158
|
+
const named = ["CI", "JENKINS_URL", "TF_BUILD", "CODEBUILD_BUILD_ID", "TEAMCITY_VERSION", "GITHUB_ACTIONS", "GITLAB_CI", "BUILDKITE", "CIRCLECI"].find((name2) => isSet(env[name2]));
|
|
9147
9159
|
if (named) return named;
|
|
9148
9160
|
return isSet(env.BUILD_NUMBER) && isSet(env.JENKINS_HOME) ? "BUILD_NUMBER with JENKINS_HOME" : null;
|
|
9149
9161
|
}
|
|
@@ -9156,10 +9168,10 @@ import { dirname as dirname2, join as join4, relative, sep } from "path";
|
|
|
9156
9168
|
import { randomBytes as randomBytes2 } from "crypto";
|
|
9157
9169
|
import { chmodSync as chmodSync3, lstatSync, mkdirSync as mkdirSync2, mkdtempSync, readdirSync, readFileSync as readFileSync3, renameSync as renameSync2, rmSync as rmSync2, writeFileSync as writeFileSync2 } from "fs";
|
|
9158
9170
|
import { dirname, join as join3 } from "path";
|
|
9159
|
-
function skillDirs(targets,
|
|
9171
|
+
function skillDirs(targets, name2) {
|
|
9160
9172
|
const dirs = [];
|
|
9161
|
-
if (targets.claude) dirs.push(join3(targets.base, ".claude", "skills",
|
|
9162
|
-
if (targets.agents) dirs.push(join3(targets.base, ".agents", "skills",
|
|
9173
|
+
if (targets.claude) dirs.push(join3(targets.base, ".claude", "skills", name2));
|
|
9174
|
+
if (targets.agents) dirs.push(join3(targets.base, ".agents", "skills", name2));
|
|
9163
9175
|
return dirs;
|
|
9164
9176
|
}
|
|
9165
9177
|
var message = (err) => err instanceof Error ? err.message : String(err);
|
|
@@ -9253,24 +9265,24 @@ function planInstall(dirs, payload) {
|
|
|
9253
9265
|
return { path, action: current === null ? "wrote" : current.equals(payload.body) ? "unchanged" : "replaced" };
|
|
9254
9266
|
});
|
|
9255
9267
|
}
|
|
9256
|
-
function refuseClashes(plan,
|
|
9268
|
+
function refuseClashes(plan, name2, force) {
|
|
9257
9269
|
const clashes = plan.filter((p) => p.action === "replaced").map((p) => p.path);
|
|
9258
9270
|
if (clashes.length > 0 && !force) {
|
|
9259
9271
|
throw new CliError(
|
|
9260
9272
|
"skill_exists",
|
|
9261
|
-
`A different ${
|
|
9273
|
+
`A different ${name2} skill is already at ${clashes.join(" and ")}.`,
|
|
9262
9274
|
EXIT.general,
|
|
9263
9275
|
"Nothing was written. Run again with --force to replace it."
|
|
9264
9276
|
);
|
|
9265
9277
|
}
|
|
9266
9278
|
}
|
|
9267
|
-
function stage(target,
|
|
9279
|
+
function stage(target, name2, archive, staged) {
|
|
9268
9280
|
const s = { target, temp: "" };
|
|
9269
9281
|
staged.push(s);
|
|
9270
9282
|
refuseLinks(target);
|
|
9271
9283
|
s.createdParent = mkdirSync2(dirname(target), { recursive: true }) ?? void 0;
|
|
9272
9284
|
refuseLinks(target);
|
|
9273
|
-
s.temp = mkdtempSync(join3(dirname(target), `.${
|
|
9285
|
+
s.temp = mkdtempSync(join3(dirname(target), `.${name2}.amdahl-tmp-`));
|
|
9274
9286
|
chmodSync3(s.temp, 493);
|
|
9275
9287
|
for (const dir of archive.dirs) mkdirSync2(join3(s.temp, dir));
|
|
9276
9288
|
for (const file of archive.files) writeFileSync2(join3(s.temp, file.path), file.bytes, { flag: "wx", mode: file.mode });
|
|
@@ -9290,14 +9302,14 @@ function rollBack(staged) {
|
|
|
9290
9302
|
if (s.createdParent) rmSync2(s.createdParent, { recursive: true, force: true });
|
|
9291
9303
|
}
|
|
9292
9304
|
}
|
|
9293
|
-
function writeFolders(plan,
|
|
9305
|
+
function writeFolders(plan, name2, archive) {
|
|
9294
9306
|
const staged = [];
|
|
9295
9307
|
let current = "";
|
|
9296
9308
|
try {
|
|
9297
9309
|
for (const p of plan) {
|
|
9298
9310
|
if (p.action === "unchanged") continue;
|
|
9299
9311
|
current = p.path;
|
|
9300
|
-
stage(p.path,
|
|
9312
|
+
stage(p.path, name2, archive, staged);
|
|
9301
9313
|
}
|
|
9302
9314
|
for (const s of staged) {
|
|
9303
9315
|
current = s.target;
|
|
@@ -9334,8 +9346,8 @@ function writeFiles(plan, body) {
|
|
|
9334
9346
|
written.push(p.path);
|
|
9335
9347
|
}
|
|
9336
9348
|
}
|
|
9337
|
-
function writeInstall(io, plan,
|
|
9338
|
-
io.uninterruptible(() => payload.type === "archive" ? writeFolders(plan,
|
|
9349
|
+
function writeInstall(io, plan, name2, payload) {
|
|
9350
|
+
io.uninterruptible(() => payload.type === "archive" ? writeFolders(plan, name2, payload.archive) : writeFiles(plan, payload.body));
|
|
9339
9351
|
}
|
|
9340
9352
|
|
|
9341
9353
|
// src/commands/skills-guide.ts
|
|
@@ -9566,8 +9578,8 @@ function catalogEntries(body) {
|
|
|
9566
9578
|
}));
|
|
9567
9579
|
}
|
|
9568
9580
|
function findConnector(entries, wanted) {
|
|
9569
|
-
const
|
|
9570
|
-
return entries.find((e) => e.type.toLowerCase() ===
|
|
9581
|
+
const key2 = wanted.toLowerCase().replace(/[\s-]+/g, "_");
|
|
9582
|
+
return entries.find((e) => e.type.toLowerCase() === key2 || e.name.toLowerCase().replace(/[\s-]+/g, "_") === key2);
|
|
9571
9583
|
}
|
|
9572
9584
|
async function connect(ctx, args) {
|
|
9573
9585
|
if (args.length > 1) throw usageError("Name one connector at a time.", `Usage: ${amdahlCommand("connect [<connector>] [--no-browser]")}`);
|
|
@@ -9635,11 +9647,11 @@ function connectionRow(c) {
|
|
|
9635
9647
|
const connector = record(c.connector);
|
|
9636
9648
|
const type = field(connector?.name) || field(c.connector_type);
|
|
9637
9649
|
const label = field(c.name);
|
|
9638
|
-
const
|
|
9650
|
+
const name2 = label && label !== type ? `${type} (${label})` : type || label;
|
|
9639
9651
|
const health = healthOf(c);
|
|
9640
9652
|
const synced = day(c.last_synced_at);
|
|
9641
9653
|
return {
|
|
9642
|
-
name: clip(
|
|
9654
|
+
name: clip(name2, 32),
|
|
9643
9655
|
kind: field(connector?.category),
|
|
9644
9656
|
health: HEALTH[health] ?? health,
|
|
9645
9657
|
synced: synced ? `synced ${synced}` : "never synced"
|
|
@@ -9661,7 +9673,7 @@ ${connectLine()}`);
|
|
|
9661
9673
|
return EXIT.ok;
|
|
9662
9674
|
}
|
|
9663
9675
|
const rows = list2.map(connectionRow);
|
|
9664
|
-
const width = (
|
|
9676
|
+
const width = (key2) => Math.max(...rows.map((r) => [...r[key2]].length));
|
|
9665
9677
|
const [w1, w2, w3] = [width("name"), width("kind"), width("health")];
|
|
9666
9678
|
const pad2 = (s, w) => s + " ".repeat(Math.max(0, w - [...s].length));
|
|
9667
9679
|
const lines = rows.map((r) => `${pad2(r.name, w1)} ${pad2(r.kind, w2)} ${pad2(r.health, w3)} ${r.synced}`.trimEnd());
|
|
@@ -9794,13 +9806,13 @@ async function sent(ctx, args) {
|
|
|
9794
9806
|
throw usageError("--sent-at must be a time with a time zone, for example 2026-11-12T09:30:00Z.");
|
|
9795
9807
|
}
|
|
9796
9808
|
const item = { run_id: id, provider, channel, sent_as: sentAs, sent_at: sentAt };
|
|
9797
|
-
for (const [flag, [
|
|
9809
|
+
for (const [flag, [key2, max]] of Object.entries(PROVIDER_IDS)) {
|
|
9798
9810
|
const value = text(flag, str(flags[flag]), max);
|
|
9799
9811
|
if (value === void 0) continue;
|
|
9800
9812
|
if (EMAIL_WHOLE_VALUE.test(value.trim()) || LINKEDIN_PROFILE.test(value.trim())) {
|
|
9801
9813
|
throw usageError(`--${flag} is the provider's own id, not an email address or a LinkedIn profile URL.`, "Amdahl stores a person only as a hash: give the address with --recipient.");
|
|
9802
9814
|
}
|
|
9803
|
-
item[
|
|
9815
|
+
item[key2] = value;
|
|
9804
9816
|
}
|
|
9805
9817
|
const sendId = typeof item.provider_send_id === "string" ? item.provider_send_id : void 0;
|
|
9806
9818
|
if (provider === "gmail" && sendId !== void 0 && !BRACKETED_MESSAGE_ID.test(sendId.trim())) {
|
|
@@ -10246,9 +10258,9 @@ async function waitForDecision(ctx, client, req) {
|
|
|
10246
10258
|
}
|
|
10247
10259
|
}
|
|
10248
10260
|
async function keysCreate(ctx) {
|
|
10249
|
-
const
|
|
10250
|
-
if (!
|
|
10251
|
-
if (
|
|
10261
|
+
const name2 = str(ctx.flags.name)?.trim();
|
|
10262
|
+
if (!name2) throw usageError("--name is required.", `Example: ${amdahlCommand('keys create --name "CI pipeline"')}`);
|
|
10263
|
+
if (name2.length > 80) throw usageError("--name must be at most 80 characters.");
|
|
10252
10264
|
const preset = str(ctx.flags.preset) ?? "read-only";
|
|
10253
10265
|
const bundle = PRESET_BUNDLES[preset];
|
|
10254
10266
|
if (!bundle) throw usageError(`--preset must be one of: ${Object.keys(PRESET_BUNDLES).join(", ")}.`);
|
|
@@ -10257,22 +10269,22 @@ async function keysCreate(ctx) {
|
|
|
10257
10269
|
if (!days) throw usageError(`--expires must be one of: ${Object.keys(EXPIRES_DAYS).join(", ")}.`);
|
|
10258
10270
|
const credential = await requireOAuthCredential(ctx);
|
|
10259
10271
|
const client = apiClient(ctx, credential);
|
|
10260
|
-
const
|
|
10272
|
+
const key2 = generateKey();
|
|
10261
10273
|
const req = await call(
|
|
10262
10274
|
() => client.cli.createKeyRequest({
|
|
10263
10275
|
action: "create",
|
|
10264
|
-
name,
|
|
10276
|
+
name: name2,
|
|
10265
10277
|
bundle_name: bundle,
|
|
10266
10278
|
expires_in_days: days,
|
|
10267
|
-
key_hash:
|
|
10268
|
-
key_prefix:
|
|
10279
|
+
key_hash: key2.hash,
|
|
10280
|
+
key_prefix: key2.prefix,
|
|
10269
10281
|
device_name: ctx.io.hostname.slice(0, 120)
|
|
10270
10282
|
})
|
|
10271
10283
|
);
|
|
10272
|
-
announce(ctx, req, `create the key "${
|
|
10284
|
+
announce(ctx, req, `create the key "${name2}"`);
|
|
10273
10285
|
const state = await waitForDecision(ctx, client, req);
|
|
10274
10286
|
const minted = state.key;
|
|
10275
|
-
if (!minted || minted.key_prefix !==
|
|
10287
|
+
if (!minted || minted.key_prefix !== key2.prefix) {
|
|
10276
10288
|
throw new CliError(
|
|
10277
10289
|
"key_mismatch",
|
|
10278
10290
|
"The approved key does not match the one this terminal generated. Nothing was printed.",
|
|
@@ -10281,7 +10293,7 @@ async function keysCreate(ctx) {
|
|
|
10281
10293
|
);
|
|
10282
10294
|
}
|
|
10283
10295
|
ctx.out.info(`Key created: ${minted.name} (${minted.key_prefix}...). Copy it now: it is shown once and stored nowhere.`);
|
|
10284
|
-
ctx.out.result({ ok: true, secret:
|
|
10296
|
+
ctx.out.result({ ok: true, secret: key2.secret, key: minted }, key2.secret);
|
|
10285
10297
|
return EXIT.ok;
|
|
10286
10298
|
}
|
|
10287
10299
|
async function workspaceId(ctx, client, fromProfile) {
|
|
@@ -10363,7 +10375,354 @@ function sentLines(runId2, lead = "Sent it?") {
|
|
|
10363
10375
|
|
|
10364
10376
|
// src/commands/batch.ts
|
|
10365
10377
|
import { existsSync as existsSync5, writeFileSync as writeFileSync4 } from "fs";
|
|
10366
|
-
import { basename as
|
|
10378
|
+
import { basename as basename3, dirname as dirname4, extname, join as join7 } from "path";
|
|
10379
|
+
|
|
10380
|
+
// src/send-to.ts
|
|
10381
|
+
import { basename as basename2 } from "path";
|
|
10382
|
+
var SEND_TO_IDS = ["instantly", "smartlead", "lemlist", "heyreach", "reply_io", "apollo", "outreach", "salesloft", "hubspot", "lgm", "woodpecker", "other"];
|
|
10383
|
+
var braces = (column) => `{{${column}}}`;
|
|
10384
|
+
var name = (column) => column;
|
|
10385
|
+
var single = (column) => `{${column}}`;
|
|
10386
|
+
var PASTE = "Paste into your step";
|
|
10387
|
+
var MENU = "Add them from the variable menu in your step";
|
|
10388
|
+
var cols = (channel, to) => channel === "email" ? `amdahl_subject and amdahl_message ${to}` : `amdahl_message ${to}`;
|
|
10389
|
+
var key = (channel, email, linkedin) => channel === "linkedin" ? linkedin : email;
|
|
10390
|
+
var SEND_TO_PRESETS = [
|
|
10391
|
+
{
|
|
10392
|
+
id: "instantly",
|
|
10393
|
+
label: "Instantly",
|
|
10394
|
+
channels: ["email"],
|
|
10395
|
+
headers: { company: "company_name" },
|
|
10396
|
+
where: "In your campaign, open Leads and choose Upload CSV.",
|
|
10397
|
+
match: (c) => `Map email to Email, and ${cols(c, "to custom variables")}.`,
|
|
10398
|
+
insert: PASTE,
|
|
10399
|
+
variable: braces
|
|
10400
|
+
},
|
|
10401
|
+
{
|
|
10402
|
+
id: "smartlead",
|
|
10403
|
+
label: "Smartlead",
|
|
10404
|
+
channels: ["email"],
|
|
10405
|
+
headers: { company: "company_name" },
|
|
10406
|
+
where: "Engage > Campaigns > your campaign > Import Leads > Import CSV.",
|
|
10407
|
+
match: (c) => `Map email to Email, and ${cols(c, "to custom variables")}.`,
|
|
10408
|
+
insert: PASTE,
|
|
10409
|
+
variable: braces
|
|
10410
|
+
},
|
|
10411
|
+
{
|
|
10412
|
+
id: "lemlist",
|
|
10413
|
+
label: "lemlist",
|
|
10414
|
+
channels: ["email", "linkedin"],
|
|
10415
|
+
headers: { first_name: "firstName", last_name: "lastName", company: "companyName", linkedin_url: "linkedinUrl" },
|
|
10416
|
+
where: "In your campaign, open Leads list > Import new leads > CSV.",
|
|
10417
|
+
match: (c) => `${key(c, "email", "linkedinUrl")} and the name columns map on their own. ${cols(c, "become custom variables")}.`,
|
|
10418
|
+
insert: PASTE,
|
|
10419
|
+
maxValue: 2e3,
|
|
10420
|
+
variable: braces
|
|
10421
|
+
},
|
|
10422
|
+
{
|
|
10423
|
+
id: "heyreach",
|
|
10424
|
+
label: "HeyReach",
|
|
10425
|
+
channels: ["linkedin"],
|
|
10426
|
+
needsNames: true,
|
|
10427
|
+
where: "Leads > Add Leads > Import from CSV.",
|
|
10428
|
+
match: () => "Map linkedin_url to the profile URL. Add a custom variable from amdahl_message.",
|
|
10429
|
+
insert: "Add amdahl_message from the Add variable menu, or paste",
|
|
10430
|
+
note: "Set a fallback message on the step: HeyReach sends it when a lead has no value. Its docs do not show the brace syntax, so use the Add variable menu if the pasted text does not turn orange.",
|
|
10431
|
+
variable: single
|
|
10432
|
+
},
|
|
10433
|
+
{
|
|
10434
|
+
id: "reply_io",
|
|
10435
|
+
label: "Reply.io",
|
|
10436
|
+
channels: ["email", "linkedin"],
|
|
10437
|
+
where: "Add contacts > Import from a CSV file.",
|
|
10438
|
+
match: (c) => `Map ${key(c, "email to Email", "linkedin_url to LinkedIn")}. Create a custom field for ${c === "email" ? "each of amdahl_subject and amdahl_message" : "amdahl_message"}.`,
|
|
10439
|
+
insert: PASTE,
|
|
10440
|
+
variable: braces
|
|
10441
|
+
},
|
|
10442
|
+
{
|
|
10443
|
+
id: "apollo",
|
|
10444
|
+
label: "Apollo",
|
|
10445
|
+
channels: ["email"],
|
|
10446
|
+
where: "Import a CSV of contacts.",
|
|
10447
|
+
match: () => "Map email to Email. Create a custom contact field for amdahl_subject and one for amdahl_message, then map to them.",
|
|
10448
|
+
insert: MENU,
|
|
10449
|
+
variable: name
|
|
10450
|
+
},
|
|
10451
|
+
{
|
|
10452
|
+
id: "outreach",
|
|
10453
|
+
label: "Outreach",
|
|
10454
|
+
channels: ["email"],
|
|
10455
|
+
where: "Actions > Bulk Create > Prospects.",
|
|
10456
|
+
match: () => "Map email to Email, amdahl_subject to Custom 1 and amdahl_message to Custom 2.",
|
|
10457
|
+
insert: PASTE,
|
|
10458
|
+
variable: (column) => column === "amdahl_subject" ? "{{custom1}}" : "{{custom2}}"
|
|
10459
|
+
},
|
|
10460
|
+
{
|
|
10461
|
+
id: "salesloft",
|
|
10462
|
+
label: "Salesloft",
|
|
10463
|
+
channels: ["email"],
|
|
10464
|
+
where: "People > Create People > Import from CSV.",
|
|
10465
|
+
match: () => "Map email to Email Address. An admin first adds a person field for amdahl_subject and one for amdahl_message, then you map to them.",
|
|
10466
|
+
insert: MENU,
|
|
10467
|
+
variable: name
|
|
10468
|
+
},
|
|
10469
|
+
{
|
|
10470
|
+
id: "hubspot",
|
|
10471
|
+
label: "HubSpot",
|
|
10472
|
+
channels: ["email"],
|
|
10473
|
+
where: "Contacts > Import, then upload the CSV.",
|
|
10474
|
+
match: () => "Map email to Email. Choose Create new property for amdahl_subject and for amdahl_message.",
|
|
10475
|
+
insert: "Add them with Personalize in your sequence email",
|
|
10476
|
+
note: "HubSpot sequences can drop line breaks from a multi-line property, so check one email before you enroll.",
|
|
10477
|
+
variable: name
|
|
10478
|
+
},
|
|
10479
|
+
{
|
|
10480
|
+
id: "lgm",
|
|
10481
|
+
label: "La Growth Machine",
|
|
10482
|
+
channels: ["linkedin"],
|
|
10483
|
+
where: "Leads > Import leads > Import CSV.",
|
|
10484
|
+
match: () => "Map linkedin_url to the profile URL. Import amdahl_message as a custom attribute.",
|
|
10485
|
+
insert: "Add it from the variable menu in your step",
|
|
10486
|
+
note: "La Growth Machine does not document the exact form of a custom attribute, so copy it from its menu.",
|
|
10487
|
+
variable: name
|
|
10488
|
+
},
|
|
10489
|
+
{
|
|
10490
|
+
id: "woodpecker",
|
|
10491
|
+
label: "Woodpecker",
|
|
10492
|
+
channels: ["email"],
|
|
10493
|
+
where: "In your campaign, choose Add prospects > Import.",
|
|
10494
|
+
match: () => "Map email to Email, amdahl_subject to Snippet 1 and amdahl_message to Snippet 2.",
|
|
10495
|
+
insert: "Add them with the {{ }} button in your step",
|
|
10496
|
+
variable: (column) => column === "amdahl_subject" ? "Snippet 1" : "Snippet 2"
|
|
10497
|
+
},
|
|
10498
|
+
{
|
|
10499
|
+
id: "other",
|
|
10500
|
+
label: "Other (any tool)",
|
|
10501
|
+
channels: ["email", "linkedin"],
|
|
10502
|
+
where: "Use the CSV import for leads in your tool.",
|
|
10503
|
+
match: (c) => `${key(c, "Map email to your email field", "Map linkedin_url to your profile URL field")}, and ${cols(c, "to custom fields")}.`,
|
|
10504
|
+
insert: "Paste into your step (most tools use this form)",
|
|
10505
|
+
variable: braces
|
|
10506
|
+
}
|
|
10507
|
+
];
|
|
10508
|
+
function presetFor(value) {
|
|
10509
|
+
const id = value.trim().toLowerCase().replace(/-/g, "_");
|
|
10510
|
+
return SEND_TO_PRESETS.find((p) => p.id === id);
|
|
10511
|
+
}
|
|
10512
|
+
var subjectColumn = "amdahl_subject";
|
|
10513
|
+
var messageColumn = "amdahl_message";
|
|
10514
|
+
var LEAD_FIELDS = [
|
|
10515
|
+
{ key: "email", names: ["email", "email_address", "work_email", "e_mail", "contact_email", "person_email", "business_email"] },
|
|
10516
|
+
{ key: "first", names: ["first_name", "firstname", "first", "given_name", "contact_first_name"] },
|
|
10517
|
+
{ key: "last", names: ["last_name", "lastname", "last", "surname", "family_name", "contact_last_name"] },
|
|
10518
|
+
{ key: "name", names: ["name", "full_name", "contact_name", "person_name", "contact"] },
|
|
10519
|
+
{ key: "company", names: ["company", "company_name", "account", "account_name", "organization", "organisation", "organization_name"] },
|
|
10520
|
+
{ key: "linkedin", names: ["linkedin", "linkedin_url", "linkedin_profile", "person_linkedin_url", "li_url", "linkedin_profile_url"] }
|
|
10521
|
+
];
|
|
10522
|
+
var norm = (h) => h.replace(/^\uFEFF/, "").trim().toLowerCase().replace(/[^\p{L}\p{N}]+/gu, "_").replace(/^_+|_+$/g, "");
|
|
10523
|
+
function autoMap(headers) {
|
|
10524
|
+
const n = headers.map(norm);
|
|
10525
|
+
const map = {};
|
|
10526
|
+
for (const f of LEAD_FIELDS) map[f.key] = n.findIndex((h) => f.names.includes(h));
|
|
10527
|
+
return map;
|
|
10528
|
+
}
|
|
10529
|
+
function leadOf(cells, map) {
|
|
10530
|
+
const cell3 = (k) => map[k] >= 0 ? (cells[map[k]] ?? "").trim() : "";
|
|
10531
|
+
const first2 = cell3("first");
|
|
10532
|
+
return { cells, email: cell3("email"), name: cell3("name") || [first2, cell3("last")].filter(Boolean).join(" "), company: cell3("company"), linkedin: cell3("linkedin") };
|
|
10533
|
+
}
|
|
10534
|
+
function stripUnverifiedMarkers(text3) {
|
|
10535
|
+
const open2 = "<unverified>";
|
|
10536
|
+
const close = "</unverified>";
|
|
10537
|
+
if (!text3.includes(open2) && !text3.includes(close)) return text3;
|
|
10538
|
+
return text3.replace(/<unverified>([\s\S]*?)<\/unverified>/g, "$1").split(open2).join("").split(close).join("");
|
|
10539
|
+
}
|
|
10540
|
+
function splitSubject(text3) {
|
|
10541
|
+
const m = text3.match(/^\s*subject\s*:\s*(.*)\r?\n/i);
|
|
10542
|
+
if (!m) return { subject: null, body: text3.trim() };
|
|
10543
|
+
return { subject: m[1]?.trim() || null, body: text3.slice(m[0].length).trim() };
|
|
10544
|
+
}
|
|
10545
|
+
function writtenOf(item) {
|
|
10546
|
+
const result = item?.result && typeof item.result === "object" && !Array.isArray(item.result) ? item.result : null;
|
|
10547
|
+
if (item?.status === "failed" || result?.ok === false) return { kind: "failed" };
|
|
10548
|
+
if (!item || item.status !== "done" || !result) return { kind: "unwritten" };
|
|
10549
|
+
if (result.outcome === "needs_input") return { kind: "needs_input" };
|
|
10550
|
+
if (typeof result.message !== "string") return { kind: "unwritten" };
|
|
10551
|
+
const { subject, body } = splitSubject(stripUnverifiedMarkers(result.message));
|
|
10552
|
+
return { kind: "written", subject: subject ?? "", body };
|
|
10553
|
+
}
|
|
10554
|
+
function cell(value) {
|
|
10555
|
+
return /[",\n\r]/.test(value) ? `"${value.replace(/"/g, '""')}"` : value;
|
|
10556
|
+
}
|
|
10557
|
+
var AMDAHL_INPUT_COLUMNS = ["message", "channel", "evidence", "on_unsupported", "facts", "rules", "item_id"];
|
|
10558
|
+
var SUBJECT_HEADERS = ["subject", "subject_line", "email_subject", "subjectline", "betreff", "objet", "sujet", "asunto", "oggetto", "onderwerp"];
|
|
10559
|
+
var CHANNEL_HEADERS = ["channel", "type", "medium"];
|
|
10560
|
+
var ADDRESS = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
10561
|
+
var isDraftHeader = (h) => ["message", "draft", "email_copy"].includes(h) || /(^|_)body(_html|_text)?$/.test(h);
|
|
10562
|
+
function draftColumn(headers, rows) {
|
|
10563
|
+
const n = headers.map(norm);
|
|
10564
|
+
const subjectCol = n.findIndex((h) => SUBJECT_HEADERS.includes(h));
|
|
10565
|
+
const channelCol = n.findIndex((h) => CHANNEL_HEADERS.includes(h));
|
|
10566
|
+
const onlyAddresses = (c) => {
|
|
10567
|
+
const cells = rows.map((r) => (r[c] ?? "").trim()).filter(Boolean);
|
|
10568
|
+
return cells.length > 0 && cells.every((v) => ADDRESS.test(v));
|
|
10569
|
+
};
|
|
10570
|
+
return n.findIndex((h, i) => isDraftHeader(h) && i !== subjectCol && i !== channelCol && !onlyAddresses(i));
|
|
10571
|
+
}
|
|
10572
|
+
function snakeHeader(header) {
|
|
10573
|
+
return header.normalize("NFKD").replace(/[\u0300-\u036f]/g, "").toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "");
|
|
10574
|
+
}
|
|
10575
|
+
function sendToFileName(listPath, preset) {
|
|
10576
|
+
const list2 = basename2(listPath).replace(/\.(csv|tsv|txt)$/i, "");
|
|
10577
|
+
const base = snakeHeader(list2).replace(/_/g, "-") || "leads";
|
|
10578
|
+
return `${base}-${preset.id.replace(/_/g, "-")}.csv`;
|
|
10579
|
+
}
|
|
10580
|
+
function namesOf(lead, map) {
|
|
10581
|
+
const at = (field3) => map[field3] >= 0 ? (lead.cells[map[field3]] ?? "").trim() : "";
|
|
10582
|
+
const parts = lead.name.split(/\s+/).filter(Boolean);
|
|
10583
|
+
return { first: at("first") || parts[0] || "", last: at("last") || (map.last >= 0 ? "" : parts.slice(1).join(" ")) };
|
|
10584
|
+
}
|
|
10585
|
+
function hasContact(lead, map, channel, preset) {
|
|
10586
|
+
if (channel === "email") return Boolean(lead.email);
|
|
10587
|
+
if (!lead.linkedin) return false;
|
|
10588
|
+
if (!preset.needsNames) return true;
|
|
10589
|
+
const { first: first2, last } = namesOf(lead, map);
|
|
10590
|
+
return Boolean(first2 && last);
|
|
10591
|
+
}
|
|
10592
|
+
function identityColumns(map, preset) {
|
|
10593
|
+
const used = /* @__PURE__ */ new Set();
|
|
10594
|
+
const columns = [];
|
|
10595
|
+
const head = (k) => preset.headers?.[k] ?? k;
|
|
10596
|
+
const take = (...fields) => fields.forEach((f) => map[f] >= 0 && used.add(map[f]));
|
|
10597
|
+
if (map.email >= 0) {
|
|
10598
|
+
take("email");
|
|
10599
|
+
columns.push({ name: "email", value: (_, l) => l.email });
|
|
10600
|
+
}
|
|
10601
|
+
if (map.name >= 0 || map.first >= 0) {
|
|
10602
|
+
take("first", "last");
|
|
10603
|
+
columns.push({ name: head("first_name"), value: (_, l) => namesOf(l, map).first });
|
|
10604
|
+
columns.push({ name: head("last_name"), value: (_, l) => namesOf(l, map).last });
|
|
10605
|
+
}
|
|
10606
|
+
if (map.company >= 0) {
|
|
10607
|
+
take("company");
|
|
10608
|
+
columns.push({ name: head("company"), value: (_, l) => l.company });
|
|
10609
|
+
}
|
|
10610
|
+
if (map.linkedin >= 0) {
|
|
10611
|
+
take("linkedin");
|
|
10612
|
+
columns.push({ name: head("linkedin_url"), value: (_, l) => l.linkedin });
|
|
10613
|
+
}
|
|
10614
|
+
return { columns, used };
|
|
10615
|
+
}
|
|
10616
|
+
function otherColumns(headers, used, taken, draft) {
|
|
10617
|
+
const out = [];
|
|
10618
|
+
headers.forEach((header, i) => {
|
|
10619
|
+
if (used.has(i) || i === draft) return;
|
|
10620
|
+
const base = snakeHeader(header) || `column_${i + 1}`;
|
|
10621
|
+
if (AMDAHL_INPUT_COLUMNS.includes(base)) return;
|
|
10622
|
+
let columnName = base;
|
|
10623
|
+
for (let n = 2; taken.has(columnName); n += 1) columnName = `${base}_${n}`;
|
|
10624
|
+
taken.add(columnName);
|
|
10625
|
+
out.push({ name: columnName, value: (_, l) => l.cells[i] ?? "" });
|
|
10626
|
+
});
|
|
10627
|
+
return out;
|
|
10628
|
+
}
|
|
10629
|
+
function buildSendToFile({ path, headers: raw, rows, channel, preset }) {
|
|
10630
|
+
const headers = raw.map((h) => h.replace(/^\uFEFF/, "").trim());
|
|
10631
|
+
const map = autoMap(headers);
|
|
10632
|
+
const leftOut = { failed: 0, unwritten: 0, needsInput: 0, noContact: 0 };
|
|
10633
|
+
const ready = [];
|
|
10634
|
+
for (const row of rows) {
|
|
10635
|
+
const lead = leadOf(row.cells, map);
|
|
10636
|
+
const written = row.written;
|
|
10637
|
+
if (written.kind === "failed") leftOut.failed += 1;
|
|
10638
|
+
else if (written.kind === "unwritten") leftOut.unwritten += 1;
|
|
10639
|
+
else if (written.kind === "needs_input") leftOut.needsInput += 1;
|
|
10640
|
+
else if (!hasContact(lead, map, channel, preset)) leftOut.noContact += 1;
|
|
10641
|
+
else ready.push({ written, lead });
|
|
10642
|
+
}
|
|
10643
|
+
const identity = identityColumns(map, preset);
|
|
10644
|
+
const taken = /* @__PURE__ */ new Set([...identity.columns.map((c) => c.name), subjectColumn, messageColumn]);
|
|
10645
|
+
const columns = [
|
|
10646
|
+
...identity.columns,
|
|
10647
|
+
...channel === "email" ? [{ name: subjectColumn, value: (w) => w.subject }] : [],
|
|
10648
|
+
{ name: messageColumn, value: (w) => w.body },
|
|
10649
|
+
...otherColumns(headers, identity.used, taken, draftColumn(headers, rows.map((r) => r.cells)))
|
|
10650
|
+
];
|
|
10651
|
+
const lines = ready.map(({ written, lead }) => columns.map((c) => cell(c.value(written, lead).replace(/\r\n?/g, "\n"))).join(","));
|
|
10652
|
+
const overLimit = preset.maxValue ? ready.filter(({ written }) => written.body.length > (preset.maxValue ?? 0)).length : 0;
|
|
10653
|
+
return {
|
|
10654
|
+
name: sendToFileName(path, preset),
|
|
10655
|
+
csv: [columns.map((c) => c.name).join(","), ...lines].join("\r\n"),
|
|
10656
|
+
ready: ready.length,
|
|
10657
|
+
leftOut,
|
|
10658
|
+
overLimit
|
|
10659
|
+
};
|
|
10660
|
+
}
|
|
10661
|
+
function leftOutLine(left, channel, preset) {
|
|
10662
|
+
const total = left.failed + left.unwritten + left.needsInput + left.noContact;
|
|
10663
|
+
if (total === 0) return null;
|
|
10664
|
+
const missing = channel === "email" ? "email" : preset.needsNames ? "LinkedIn URL or full name" : "LinkedIn URL";
|
|
10665
|
+
const parts = [
|
|
10666
|
+
left.failed ? `${left.failed} failed` : null,
|
|
10667
|
+
left.unwritten ? `${left.unwritten} not written yet` : null,
|
|
10668
|
+
left.needsInput ? `${left.needsInput} needed input` : null,
|
|
10669
|
+
left.noContact ? `${left.noContact} with no ${missing}` : null
|
|
10670
|
+
].filter((p) => p !== null);
|
|
10671
|
+
return `${total} left out: ${parts.join(", ")}.`;
|
|
10672
|
+
}
|
|
10673
|
+
function guideLines(preset, channel) {
|
|
10674
|
+
const email = channel === "email";
|
|
10675
|
+
const variables = [...email ? [`Subject ${preset.variable(subjectColumn)}`] : [], `${email ? "Body" : "Message"} ${preset.variable(messageColumn)}`];
|
|
10676
|
+
return [`Import: ${preset.where}`, preset.match(channel), `${preset.insert}: ${variables.join(", ")}`];
|
|
10677
|
+
}
|
|
10678
|
+
function readyLine(ready, preset) {
|
|
10679
|
+
return `${ready} ${ready === 1 ? "message" : "messages"} ready ${preset.id === "other" ? "to import" : `for ${preset.label}`}`;
|
|
10680
|
+
}
|
|
10681
|
+
function overLimitLine(over, preset) {
|
|
10682
|
+
return `${over} ${over === 1 ? "message is" : "messages are"} over ${preset.label}'s ${(preset.maxValue ?? 0).toLocaleString("en-US")} character limit for a variable.`;
|
|
10683
|
+
}
|
|
10684
|
+
var NO_FILE = ["gmail", "outlook"];
|
|
10685
|
+
function toolFor(value) {
|
|
10686
|
+
const preset = presetFor(value);
|
|
10687
|
+
if (preset) return preset;
|
|
10688
|
+
const lower = value.trim().toLowerCase();
|
|
10689
|
+
if (NO_FILE.includes(lower)) {
|
|
10690
|
+
throw usageError(`${lower === "gmail" ? "Gmail" : "Outlook"} sends from a mailbox, so it has no import file.`, "Use --for other for any tool that imports a CSV.");
|
|
10691
|
+
}
|
|
10692
|
+
throw usageError(`--for must be one of: ${SEND_TO_IDS.join(", ")}.`, "Use other for a tool that is not listed.");
|
|
10693
|
+
}
|
|
10694
|
+
function planSendTo(preset, list2, flagChannel) {
|
|
10695
|
+
if (list2.kind !== "csv" || !list2.header) {
|
|
10696
|
+
throw usageError("--for needs a CSV list: the import file keeps your list's columns.", `${list2.path} is not a CSV. Make one, or leave --for out.`);
|
|
10697
|
+
}
|
|
10698
|
+
const valid = (c) => c === "email" || c === "linkedin";
|
|
10699
|
+
const own = new Set(list2.items.map((i) => i.channel).filter(valid));
|
|
10700
|
+
if (valid(flagChannel)) own.add(flagChannel);
|
|
10701
|
+
if (own.size > 1) {
|
|
10702
|
+
throw usageError("--for writes one channel at a time, and this list has both email and LinkedIn rows.", `Split ${list2.path} by channel, and run each part with --for.`);
|
|
10703
|
+
}
|
|
10704
|
+
const only = preset.channels.length === 1 ? preset.channels[0] : void 0;
|
|
10705
|
+
const channel = [...own][0] ?? only;
|
|
10706
|
+
if (!channel) {
|
|
10707
|
+
throw usageError(`${preset.label} takes email and LinkedIn lists, so --for needs to know which this is.`, "Add --channel email or --channel linkedin.");
|
|
10708
|
+
}
|
|
10709
|
+
if (!preset.channels.includes(channel)) {
|
|
10710
|
+
throw usageError(`${preset.label} takes ${preset.channels[0] === "email" ? "email" : "LinkedIn"} lists only, and this one is ${channel === "email" ? "email" : "LinkedIn"}.`, "Pick a tool for this channel, or use --for other.");
|
|
10711
|
+
}
|
|
10712
|
+
const map = autoMap(list2.header);
|
|
10713
|
+
if (channel === "email" && map.email < 0) {
|
|
10714
|
+
throw usageError(`${list2.path} has no email column.`, "Name the column email, email_address or work_email, so the tool can import it.");
|
|
10715
|
+
}
|
|
10716
|
+
if (channel === "linkedin" && map.linkedin < 0) {
|
|
10717
|
+
throw usageError(`${list2.path} has no LinkedIn URL column.`, "Name the column linkedin_url, linkedin or linkedin_profile, so the tool can import it.");
|
|
10718
|
+
}
|
|
10719
|
+
if (channel === "linkedin" && preset.needsNames && map.name < 0 && !(map.first >= 0 && map.last >= 0)) {
|
|
10720
|
+
throw usageError(`${preset.label} needs a first and a last name for each lead, and ${list2.path} has no name columns.`, "Add first_name and last_name columns, or one name column.");
|
|
10721
|
+
}
|
|
10722
|
+
return { preset, channel };
|
|
10723
|
+
}
|
|
10724
|
+
|
|
10725
|
+
// src/commands/batch.ts
|
|
10367
10726
|
var PLATFORM4 = "/api/platform/v1";
|
|
10368
10727
|
var BATCH_WAIT_MS = 15e3;
|
|
10369
10728
|
var PAGE = 100;
|
|
@@ -10378,52 +10737,52 @@ function parseCsv(text3) {
|
|
|
10378
10737
|
const rows = [];
|
|
10379
10738
|
const lines = [];
|
|
10380
10739
|
let row = [];
|
|
10381
|
-
let
|
|
10740
|
+
let cell3 = "";
|
|
10382
10741
|
let quoted = false;
|
|
10383
10742
|
let line = 1;
|
|
10384
10743
|
let rowLine = 1;
|
|
10385
10744
|
let touched = false;
|
|
10386
10745
|
const src = text3.replace(/^\uFEFF/, "");
|
|
10387
10746
|
const endRow = () => {
|
|
10388
|
-
row.push(
|
|
10389
|
-
if (touched || row.length > 1 ||
|
|
10747
|
+
row.push(cell3);
|
|
10748
|
+
if (touched || row.length > 1 || cell3 !== "") {
|
|
10390
10749
|
rows.push(row);
|
|
10391
10750
|
lines.push(rowLine);
|
|
10392
10751
|
}
|
|
10393
10752
|
row = [];
|
|
10394
|
-
|
|
10753
|
+
cell3 = "";
|
|
10395
10754
|
touched = false;
|
|
10396
10755
|
};
|
|
10397
10756
|
for (let i = 0; i < src.length; i++) {
|
|
10398
10757
|
const c = src[i];
|
|
10399
10758
|
if (quoted) {
|
|
10400
10759
|
if (c === '"' && src[i + 1] === '"') {
|
|
10401
|
-
|
|
10760
|
+
cell3 += '"';
|
|
10402
10761
|
i++;
|
|
10403
10762
|
} else if (c === '"') quoted = false;
|
|
10404
10763
|
else if (c === "\r" && src[i + 1] === "\n") continue;
|
|
10405
10764
|
else {
|
|
10406
10765
|
if (c === "\n") line++;
|
|
10407
|
-
|
|
10766
|
+
cell3 += c;
|
|
10408
10767
|
}
|
|
10409
10768
|
continue;
|
|
10410
10769
|
}
|
|
10411
|
-
if (c === '"' &&
|
|
10770
|
+
if (c === '"' && cell3 === "") {
|
|
10412
10771
|
quoted = true;
|
|
10413
10772
|
touched = true;
|
|
10414
10773
|
} else if (c === ",") {
|
|
10415
|
-
row.push(
|
|
10416
|
-
|
|
10774
|
+
row.push(cell3);
|
|
10775
|
+
cell3 = "";
|
|
10417
10776
|
touched = true;
|
|
10418
10777
|
} else if (c === "\n" || c === "\r") {
|
|
10419
10778
|
if (c === "\r" && src[i + 1] === "\n") i++;
|
|
10420
10779
|
endRow();
|
|
10421
10780
|
line++;
|
|
10422
10781
|
rowLine = line;
|
|
10423
|
-
} else
|
|
10782
|
+
} else cell3 += c;
|
|
10424
10783
|
}
|
|
10425
10784
|
if (quoted) throw usageError(`A quoted CSV field that starts on line ${rowLine} never ends.`);
|
|
10426
|
-
if (
|
|
10785
|
+
if (cell3 !== "" || row.length > 0 || touched) endRow();
|
|
10427
10786
|
return { rows, lines };
|
|
10428
10787
|
}
|
|
10429
10788
|
function csvCell(value) {
|
|
@@ -10432,8 +10791,8 @@ function csvCell(value) {
|
|
|
10432
10791
|
function toCsv(rows) {
|
|
10433
10792
|
return rows.map((r) => r.map(csvCell).join(",")).join("\n") + "\n";
|
|
10434
10793
|
}
|
|
10435
|
-
function perLine(
|
|
10436
|
-
return
|
|
10794
|
+
function perLine(cell3) {
|
|
10795
|
+
return cell3.split(/\r?\n/).map((s) => s.trim()).filter(Boolean);
|
|
10437
10796
|
}
|
|
10438
10797
|
function csvList(path, text3) {
|
|
10439
10798
|
const { rows, lines } = parseCsv(text3);
|
|
@@ -10455,11 +10814,11 @@ function csvList(path, text3) {
|
|
|
10455
10814
|
}
|
|
10456
10815
|
const item = {};
|
|
10457
10816
|
const context = {};
|
|
10458
|
-
names.forEach((
|
|
10817
|
+
names.forEach((name2, j) => {
|
|
10459
10818
|
const value = row[j] ?? "";
|
|
10460
|
-
if (!CSV_COLUMNS.includes(
|
|
10461
|
-
if (
|
|
10462
|
-
else item[
|
|
10819
|
+
if (!CSV_COLUMNS.includes(name2) || !value.trim()) return;
|
|
10820
|
+
if (name2 === "facts" || name2 === "rules") context[name2] = perLine(value);
|
|
10821
|
+
else item[name2] = name2 === "message" ? value : name2 === "channel" ? value.trim().toLowerCase() : value.trim();
|
|
10463
10822
|
});
|
|
10464
10823
|
if (Object.keys(context).length > 0) item.context = context;
|
|
10465
10824
|
return item;
|
|
@@ -10494,13 +10853,13 @@ function readList(path) {
|
|
|
10494
10853
|
}
|
|
10495
10854
|
function resultsPath(path, kind) {
|
|
10496
10855
|
const ext = extname(path);
|
|
10497
|
-
const stem =
|
|
10856
|
+
const stem = basename3(path, ext);
|
|
10498
10857
|
return join7(dirname4(path), `${stem}.optimized.${kind === "csv" ? "csv" : "jsonl"}`);
|
|
10499
10858
|
}
|
|
10500
10859
|
function withDefaults(items, defaults) {
|
|
10501
10860
|
return items.map((item) => {
|
|
10502
10861
|
const merged = { ...item };
|
|
10503
|
-
for (const [
|
|
10862
|
+
for (const [key2, value] of Object.entries(defaults)) if (merged[key2] === void 0) merged[key2] = value;
|
|
10504
10863
|
const shared = record(defaults.context);
|
|
10505
10864
|
const own = record(item.context);
|
|
10506
10865
|
if (shared && own) merged.context = { ...shared, ...own };
|
|
@@ -10566,14 +10925,14 @@ async function allItems(ctx, credential, id) {
|
|
|
10566
10925
|
} while (cursor);
|
|
10567
10926
|
return { batch, items };
|
|
10568
10927
|
}
|
|
10569
|
-
function neutralise(
|
|
10570
|
-
return /^[=+\-@\t\r]/.test(
|
|
10928
|
+
function neutralise(cell3) {
|
|
10929
|
+
return /^[=+\-@\t\r]/.test(cell3) ? `'${cell3}` : cell3;
|
|
10571
10930
|
}
|
|
10572
10931
|
var RESULT_COLUMNS = ["optimized_message", "status", "summary", "run_id", "error"];
|
|
10573
10932
|
function resultColumnNames(header) {
|
|
10574
10933
|
const taken = new Set(header.map((h) => h.trim().toLowerCase()));
|
|
10575
|
-
return RESULT_COLUMNS.map((
|
|
10576
|
-
let candidate =
|
|
10934
|
+
return RESULT_COLUMNS.map((name2) => {
|
|
10935
|
+
let candidate = name2;
|
|
10577
10936
|
while (taken.has(candidate)) candidate = `amdahl_${candidate}`;
|
|
10578
10937
|
taken.add(candidate);
|
|
10579
10938
|
return candidate;
|
|
@@ -10593,18 +10952,67 @@ function resultsFile(list2, id, cwd) {
|
|
|
10593
10952
|
function assertFree(path, force) {
|
|
10594
10953
|
if (!force && existsSync5(path)) throw usageError(`${path} already exists.`, "Move it, or add --force to replace it.");
|
|
10595
10954
|
}
|
|
10596
|
-
function
|
|
10955
|
+
function writeNew(path, text3, force, pickUp) {
|
|
10956
|
+
try {
|
|
10957
|
+
writeFileSync4(path, text3, { flag: force ? "w" : "wx" });
|
|
10958
|
+
} catch (err) {
|
|
10959
|
+
if (err?.code === "EEXIST") {
|
|
10960
|
+
throw usageError(`${path} already exists.`, `Move it, or add --force to replace it. The batch is done, and you can read it again: ${pickUp}`);
|
|
10961
|
+
}
|
|
10962
|
+
throw err;
|
|
10963
|
+
}
|
|
10964
|
+
}
|
|
10965
|
+
function writeResults(list2, id, items, cwd, force, contexts, pickUp) {
|
|
10597
10966
|
const byIndex = new Map(items.map((i) => [i.index, i]));
|
|
10598
10967
|
const path = resultsFile(list2, id, cwd);
|
|
10599
|
-
const flag = force ? "w" : "wx";
|
|
10600
10968
|
if (list2?.kind === "csv" && list2.header && list2.rows) {
|
|
10601
10969
|
const rows = [[...list2.header, ...resultColumnNames(list2.header)], ...list2.rows.map((row, i) => [...row, ...resultCells(byIndex.get(i), contexts[i])])];
|
|
10602
|
-
|
|
10970
|
+
writeNew(path, toCsv(rows.map((row) => row.map(neutralise))), force, pickUp);
|
|
10603
10971
|
return path;
|
|
10604
10972
|
}
|
|
10605
|
-
|
|
10973
|
+
writeNew(path, items.map((i) => JSON.stringify(i)).join("\n") + "\n", force, pickUp);
|
|
10606
10974
|
return path;
|
|
10607
10975
|
}
|
|
10976
|
+
function writeSendTo(plan, list2, items, force, pickUp) {
|
|
10977
|
+
const byIndex = new Map(items.map((i) => [i.index, i]));
|
|
10978
|
+
const built = buildSendToFile({
|
|
10979
|
+
path: list2.path,
|
|
10980
|
+
headers: list2.header ?? [],
|
|
10981
|
+
rows: (list2.rows ?? []).map((cells, i) => ({ cells, written: writtenOf(byIndex.get(i)) })),
|
|
10982
|
+
channel: plan.channel,
|
|
10983
|
+
preset: plan.preset
|
|
10984
|
+
});
|
|
10985
|
+
if (built.ready === 0) return { built, path: null };
|
|
10986
|
+
const path = join7(dirname4(list2.path), built.name);
|
|
10987
|
+
writeNew(path, built.csv, force, pickUp);
|
|
10988
|
+
return { built, path };
|
|
10989
|
+
}
|
|
10990
|
+
function sendToJson(plan, sent2) {
|
|
10991
|
+
const { leftOut, ready, overLimit } = sent2.built;
|
|
10992
|
+
return {
|
|
10993
|
+
tool: plan.preset.id,
|
|
10994
|
+
channel: plan.channel,
|
|
10995
|
+
file: sent2.path,
|
|
10996
|
+
ready,
|
|
10997
|
+
left_out: { failed: leftOut.failed, not_written: leftOut.unwritten, needs_input: leftOut.needsInput, no_contact: leftOut.noContact },
|
|
10998
|
+
over_limit: overLimit
|
|
10999
|
+
};
|
|
11000
|
+
}
|
|
11001
|
+
function printSendTo(ctx, plan, sent2) {
|
|
11002
|
+
const { out } = ctx;
|
|
11003
|
+
const { preset, channel } = plan;
|
|
11004
|
+
const left = leftOutLine(sent2.built.leftOut, channel, preset);
|
|
11005
|
+
if (!sent2.path) {
|
|
11006
|
+
out.info(`Nothing to send to ${preset.label}.${left ? ` ${left}` : ""}`);
|
|
11007
|
+
return;
|
|
11008
|
+
}
|
|
11009
|
+
out.result({}, `Import file${preset.id === "other" ? "" : ` for ${preset.label}`}: ${sent2.path}`);
|
|
11010
|
+
out.info(`${readyLine(sent2.built.ready, preset)}.${left ? ` ${left}` : ""}`);
|
|
11011
|
+
const steps = guideLines(preset, channel).map((line, i) => `${i + 1}. ${line}`);
|
|
11012
|
+
const notes = [preset.note, sent2.built.overLimit > 0 ? overLimitLine(sent2.built.overLimit, preset) : void 0].filter((n) => Boolean(n));
|
|
11013
|
+
out.info(wrap(steps.join("\n"), COLUMNS, " ").join("\n"));
|
|
11014
|
+
for (const note of notes) out.info(wrap(note, COLUMNS).join("\n"));
|
|
11015
|
+
}
|
|
10608
11016
|
function withLine(err, list2) {
|
|
10609
11017
|
if (!(err instanceof CliError)) return err;
|
|
10610
11018
|
const index = /\$\.items\[(\d+)\]/.exec(err.message)?.[1];
|
|
@@ -10612,7 +11020,8 @@ function withLine(err, list2) {
|
|
|
10612
11020
|
if (line === void 0) return err;
|
|
10613
11021
|
return new CliError(err.code, err.message, err.exit, `items[${index}] is line ${line} of ${list2.path}.`, err.detail, err.data);
|
|
10614
11022
|
}
|
|
10615
|
-
async function optimizeList(ctx,
|
|
11023
|
+
async function optimizeList(ctx, requested) {
|
|
11024
|
+
let defaults = requested;
|
|
10616
11025
|
const { out, flags } = ctx;
|
|
10617
11026
|
const listPath = str(flags.list);
|
|
10618
11027
|
const resume = str(flags.batch);
|
|
@@ -10623,7 +11032,15 @@ async function optimizeList(ctx, defaults) {
|
|
|
10623
11032
|
if (resume && !BATCH_ID.test(resume)) {
|
|
10624
11033
|
throw usageError("--batch needs a batch id: a UUID like the one `amdahl optimize --list` printed.");
|
|
10625
11034
|
}
|
|
11035
|
+
const forFlag = str(flags.for);
|
|
11036
|
+
if (typeof flags.for === "string" && !forFlag) throw usageError("--for needs a tool.", `One of: ${SEND_TO_IDS.join(", ")}.`);
|
|
11037
|
+
if (forFlag && !listPath) throw usageError("--for needs the list: add --list <file.csv>.");
|
|
11038
|
+
const preset = forFlag ? toolFor(forFlag) : null;
|
|
10626
11039
|
const list2 = listPath ? readList(listPath) : null;
|
|
11040
|
+
const plan = preset && list2 ? planSendTo(preset, list2, typeof defaults.channel === "string" ? defaults.channel : void 0) : null;
|
|
11041
|
+
if (plan) defaults = { ...defaults, channel: defaults.channel ?? plan.channel };
|
|
11042
|
+
const forPart = plan ? ` --for ${plan.preset.id}${plan.preset.channels.length > 1 ? ` --channel ${plan.channel}` : ""}` : "";
|
|
11043
|
+
const pickUpFor = (batchId) => amdahlCommand(`optimize ${listPath ? `--list ${shellWord(listPath, ctx.io.platform)} ` : ""}--batch ${batchId}${forPart}`);
|
|
10627
11044
|
if (list2?.ignored?.length) {
|
|
10628
11045
|
const shown = list2.ignored.slice(0, 6).join(", ");
|
|
10629
11046
|
const more = list2.ignored.length > 6 ? ` and ${list2.ignored.length - 6} more` : "";
|
|
@@ -10634,6 +11051,7 @@ async function optimizeList(ctx, defaults) {
|
|
|
10634
11051
|
}
|
|
10635
11052
|
const force = flags.force === true;
|
|
10636
11053
|
if (!out.json && flags["no-wait"] !== true) assertFree(resultsFile(list2, resume ?? "", ctx.io.cwd), force);
|
|
11054
|
+
if (plan && list2 && flags["no-wait"] !== true) assertFree(join7(dirname4(list2.path), sendToFileName(list2.path, plan.preset)), force);
|
|
10637
11055
|
const credential = await resolveCredential(ctx);
|
|
10638
11056
|
let id = resume ?? "";
|
|
10639
11057
|
let first2 = null;
|
|
@@ -10657,7 +11075,7 @@ async function optimizeList(ctx, defaults) {
|
|
|
10657
11075
|
}
|
|
10658
11076
|
id = field(first2.batch_id);
|
|
10659
11077
|
if (!id) throw new CliError("no_batch_id", "Amdahl accepted the list but sent no batch id.", EXIT.general);
|
|
10660
|
-
const pickUp =
|
|
11078
|
+
const pickUp = pickUpFor(id);
|
|
10661
11079
|
if (flags["no-wait"] === true) {
|
|
10662
11080
|
out.result({ ...first2, ok: true }, `Queued ${count(list2.items.length, "message")} as batch ${id}.
|
|
10663
11081
|
Get the results: ${pickUp}`);
|
|
@@ -10672,17 +11090,21 @@ Get the results: ${pickUp}`);
|
|
|
10672
11090
|
const { batch, items } = await allItems(ctx, credential, id);
|
|
10673
11091
|
const failed = items.filter((i) => i.status === "failed" || record(i.result)?.ok === false).length;
|
|
10674
11092
|
if (out.json) {
|
|
10675
|
-
|
|
10676
|
-
|
|
11093
|
+
const sent3 = plan && list2 ? writeSendTo(plan, list2, items, force, pickUpFor(id)) : null;
|
|
11094
|
+
const ok = failed === 0 && (!sent3 || sent3.built.ready > 0);
|
|
11095
|
+
out.result({ ...batch, ok, items, next_cursor: null, ...plan && sent3 ? { send_to: sendToJson(plan, sent3) } : {} });
|
|
11096
|
+
return ok ? EXIT.ok : EXIT.general;
|
|
10677
11097
|
}
|
|
10678
11098
|
const contexts = list2 ? withDefaults(list2.items, defaults).map((item) => item.context) : [];
|
|
10679
|
-
const path = writeResults(list2, id, items, ctx.io.cwd, force, contexts);
|
|
11099
|
+
const path = writeResults(list2, id, items, ctx.io.cwd, force, contexts, pickUpFor(id));
|
|
10680
11100
|
const done = items.length - failed;
|
|
10681
11101
|
out.info(`${done} of ${count(items.length, "message")} optimized${failed ? `, ${failed} failed` : ""}.`);
|
|
10682
11102
|
out.result({}, `Results: ${path}`);
|
|
11103
|
+
const sent2 = plan && list2 ? writeSendTo(plan, list2, items, force, pickUpFor(id)) : null;
|
|
11104
|
+
if (plan && sent2) printSendTo(ctx, plan, sent2);
|
|
10683
11105
|
const runId2 = items.map((i) => field(record(i.result)?.run_id)).find(Boolean);
|
|
10684
11106
|
for (const line of sentLines(runId2, "Sent one?")) out.info(line);
|
|
10685
|
-
return failed === 0 ? EXIT.ok : EXIT.general;
|
|
11107
|
+
return failed === 0 && (!sent2 || sent2.built.ready > 0) ? EXIT.ok : EXIT.general;
|
|
10686
11108
|
}
|
|
10687
11109
|
|
|
10688
11110
|
// src/commands/optimize.ts
|
|
@@ -10943,6 +11365,7 @@ async function optimize(ctx, args) {
|
|
|
10943
11365
|
}
|
|
10944
11366
|
if (ctx.flags["no-wait"] === true) throw usageError("--no-wait goes with --list <file>.");
|
|
10945
11367
|
if (ctx.flags.force === true) throw usageError("--force goes with --list <file>.");
|
|
11368
|
+
if (ctx.flags.for !== void 0) throw usageError("--for goes with --list <file.csv>.");
|
|
10946
11369
|
let files = args;
|
|
10947
11370
|
if (files.length === 0) {
|
|
10948
11371
|
if (atTerminal(ctx)) return optimizePasted(ctx);
|
|
@@ -10994,7 +11417,7 @@ var SYNTHESIZED_ID = "answer-text";
|
|
|
10994
11417
|
var MAX_TABLE_ROWS = 25;
|
|
10995
11418
|
var MAX_CELL_LINES = 4;
|
|
10996
11419
|
var MIN_COLUMN = 6;
|
|
10997
|
-
function
|
|
11420
|
+
function cell2(value) {
|
|
10998
11421
|
if (typeof value === "number") return String(value);
|
|
10999
11422
|
return typeof value === "string" ? field(value).replace(/\s+/g, " ") : "";
|
|
11000
11423
|
}
|
|
@@ -11070,8 +11493,8 @@ function dataTable(block) {
|
|
|
11070
11493
|
const columns = records(block.columns).filter((c) => field(c.key));
|
|
11071
11494
|
const data = records(block.data);
|
|
11072
11495
|
if (columns.length === 0 || data.length === 0) return [];
|
|
11073
|
-
const labels = columns.map((c) =>
|
|
11074
|
-
return asciiTable(labels, data.map((row) => columns.map((c) =>
|
|
11496
|
+
const labels = columns.map((c) => cell2(c.label) || cell2(c.key));
|
|
11497
|
+
return asciiTable(labels, data.map((row) => columns.map((c) => cell2(row[field(c.key)]))));
|
|
11075
11498
|
}
|
|
11076
11499
|
function prose(markdown) {
|
|
11077
11500
|
return plainMarkdown(paragraphs(markdown).replace(/<\s*unverified\s*>([^<]*)<\s*\/\s*unverified\s*>/gi, "$1 (unverified)"));
|
|
@@ -11095,7 +11518,7 @@ function renderBlock(block, answer) {
|
|
|
11095
11518
|
const data = record(block.data);
|
|
11096
11519
|
const value = data?.value ?? block.value;
|
|
11097
11520
|
const delta = field(data?.delta ?? block.delta);
|
|
11098
|
-
const shown = value === void 0 ? "" :
|
|
11521
|
+
const shown = value === void 0 ? "" : cell2(value);
|
|
11099
11522
|
return wrap(`${field(block.label)}: ${shown}${delta ? ` (${delta})` : ""}`);
|
|
11100
11523
|
}
|
|
11101
11524
|
case "citation": {
|
|
@@ -11144,8 +11567,8 @@ var TEXT_FIELDS = ["content_preview", "text", "quote", "snippet", "excerpt", "co
|
|
|
11144
11567
|
var WHO_FIELDS = ["speaker", "speaker_name", "account_name", "company_name", "owner_name", "deal_stage_label", "speaker_type"];
|
|
11145
11568
|
var AMOUNT_FIELDS = ["deal_amount", "amount"];
|
|
11146
11569
|
function first(row, names) {
|
|
11147
|
-
for (const
|
|
11148
|
-
const value = row[
|
|
11570
|
+
for (const name2 of names) {
|
|
11571
|
+
const value = row[name2];
|
|
11149
11572
|
if (typeof value === "string" && value.trim()) return field(value);
|
|
11150
11573
|
if (typeof value === "number") return String(value);
|
|
11151
11574
|
}
|
|
@@ -11324,12 +11747,12 @@ var TRY_IN = {
|
|
|
11324
11747
|
};
|
|
11325
11748
|
var CODEX_TRY = `Run codex, paste an email and say: ${ASK}`;
|
|
11326
11749
|
var CODEX_LOGIN = "codex mcp login amdahl";
|
|
11327
|
-
function toolScreen(
|
|
11750
|
+
function toolScreen(name2, already) {
|
|
11328
11751
|
return [
|
|
11329
|
-
already ? `\u2713 ${
|
|
11330
|
-
`One step left, in ${
|
|
11331
|
-
` 1. ${SIGN_IN[
|
|
11332
|
-
` 2. ${TRY_IN[
|
|
11752
|
+
already ? `\u2713 ${name2} already has Amdahl.` : `\u2713 Added Amdahl to ${name2}.`,
|
|
11753
|
+
`One step left, in ${name2}:`,
|
|
11754
|
+
` 1. ${SIGN_IN[name2] ?? ""}`,
|
|
11755
|
+
` 2. ${TRY_IN[name2] ?? ""}`
|
|
11333
11756
|
];
|
|
11334
11757
|
}
|
|
11335
11758
|
function whatNextLines() {
|
|
@@ -11616,8 +12039,8 @@ async function tryHere(ctx, say, lead) {
|
|
|
11616
12039
|
say(`\u2713 Signed in \xB7 ${printable(signedIn.workspace.name)}`);
|
|
11617
12040
|
if (verbose) say(` ${signedInLine(ctx, signedIn)}`);
|
|
11618
12041
|
} else {
|
|
11619
|
-
const
|
|
11620
|
-
out.info(`Amdahl rejected the key in ${
|
|
12042
|
+
const name2 = who.source === "flag" ? "--api-key" : who.source.slice("env:".length);
|
|
12043
|
+
out.info(`Amdahl rejected the key in ${name2}, so a message can't be tried here. Fix it, or unset it and run \`${amdahlCommand("login")}\`.`);
|
|
11621
12044
|
return EXIT.unauthenticated;
|
|
11622
12045
|
}
|
|
11623
12046
|
return optimizePasted(ctx);
|
|
@@ -11747,9 +12170,9 @@ function readTar(tar) {
|
|
|
11747
12170
|
if (header.toString("latin1", 257, 263) !== "ustar\0" || header.toString("latin1", 263, 265) !== "00") {
|
|
11748
12171
|
throw new ArchiveError("its tar is not ustar");
|
|
11749
12172
|
}
|
|
11750
|
-
const
|
|
12173
|
+
const name2 = field2(header, 0, 100);
|
|
11751
12174
|
const prefix2 = field2(header, 345, 155);
|
|
11752
|
-
let path = prefix2 ? `${prefix2}/${
|
|
12175
|
+
let path = prefix2 ? `${prefix2}/${name2}` : name2;
|
|
11753
12176
|
const type = String.fromCharCode(header[156]);
|
|
11754
12177
|
const size = octal(header, 124, 12);
|
|
11755
12178
|
const mode = octal(header, 100, 8);
|
|
@@ -11761,22 +12184,22 @@ function readTar(tar) {
|
|
|
11761
12184
|
}
|
|
11762
12185
|
if (isDir && path.endsWith("/")) path = path.slice(0, -1);
|
|
11763
12186
|
checkPath(path);
|
|
11764
|
-
const
|
|
11765
|
-
const parts =
|
|
12187
|
+
const key2 = path.toLowerCase();
|
|
12188
|
+
const parts = key2.split("/");
|
|
11766
12189
|
for (let i = 1; i < parts.length; i += 1) {
|
|
11767
12190
|
const parent = parts.slice(0, i).join("/");
|
|
11768
12191
|
const kind = seen.get(parent);
|
|
11769
12192
|
if (kind === "file") throw new ArchiveError(`it puts ${JSON.stringify(path)} inside a file`);
|
|
11770
12193
|
if (!kind) seen.set(parent, "implied");
|
|
11771
12194
|
}
|
|
11772
|
-
const before = seen.get(
|
|
12195
|
+
const before = seen.get(key2);
|
|
11773
12196
|
if (before === "file" || before === "dir" || before === "implied" && !isDir) {
|
|
11774
12197
|
throw new ArchiveError(`it lists ${JSON.stringify(path)} twice`);
|
|
11775
12198
|
}
|
|
11776
12199
|
const start = at + BLOCK;
|
|
11777
12200
|
if (isDir) {
|
|
11778
12201
|
if (size !== 0) throw new ArchiveError(`its folder ${JSON.stringify(path)} has a size`);
|
|
11779
|
-
seen.set(
|
|
12202
|
+
seen.set(key2, "dir");
|
|
11780
12203
|
dirs.push(path);
|
|
11781
12204
|
} else {
|
|
11782
12205
|
if (!FILE_MODES.has(mode & 4095)) {
|
|
@@ -11786,7 +12209,7 @@ function readTar(tar) {
|
|
|
11786
12209
|
unpacked += size;
|
|
11787
12210
|
if (unpacked > MAX_UNPACKED_BYTES) throw new ArchiveError(`its files come to more than ${MAX_UNPACKED_BYTES / 1024 / 1024} MB`, true);
|
|
11788
12211
|
if (start + size > tar.length) throw new ArchiveError(`its tar is cut short inside ${JSON.stringify(path)}`);
|
|
11789
|
-
seen.set(
|
|
12212
|
+
seen.set(key2, "file");
|
|
11790
12213
|
files.push({ path, bytes: Buffer.from(tar.subarray(start, start + size)), mode: mode & 4095 });
|
|
11791
12214
|
}
|
|
11792
12215
|
at = start + Math.ceil(size / BLOCK) * BLOCK;
|
|
@@ -11851,8 +12274,8 @@ function canAsk(ctx) {
|
|
|
11851
12274
|
async function confirmWarning(ctx, ref, site, warning) {
|
|
11852
12275
|
const { out } = ctx;
|
|
11853
12276
|
const host = new URL(site).host;
|
|
11854
|
-
const
|
|
11855
|
-
const head = warning.result === "fail" ? `${
|
|
12277
|
+
const name2 = `${ref.publisher}/${ref.skill}`;
|
|
12278
|
+
const head = warning.result === "fail" ? `${name2} failed ${host}'s security review.` : `${host}'s security review flagged ${name2}.`;
|
|
11856
12279
|
out.info([out.bold(`Warning: ${head}`), ` ${warning.text}`, ` See what was flagged: ${skillPage(site, ref)}`].join("\n"));
|
|
11857
12280
|
if (ctx.flags["accept-warning"] === true) {
|
|
11858
12281
|
out.info("Installing it anyway, because of --accept-warning.");
|
|
@@ -11861,7 +12284,7 @@ async function confirmWarning(ctx, ref, site, warning) {
|
|
|
11861
12284
|
if (!canAsk(ctx)) {
|
|
11862
12285
|
throw new CliError(
|
|
11863
12286
|
"skill_flagged",
|
|
11864
|
-
`Did not install ${
|
|
12287
|
+
`Did not install ${name2}, because the security review flagged it. Nothing was written.`,
|
|
11865
12288
|
EXIT.flagged,
|
|
11866
12289
|
"Show this warning to the person you are working for. Once they agree, run the same command again with --accept-warning.",
|
|
11867
12290
|
void 0,
|
|
@@ -12052,10 +12475,10 @@ function checkSkillMd(body, what, ref) {
|
|
|
12052
12475
|
} catch (err) {
|
|
12053
12476
|
throw bad(`its front matter could not be read (${printable(err instanceof Error ? err.message : String(err))})`);
|
|
12054
12477
|
}
|
|
12055
|
-
const { name, description, version, metadata } = meta && typeof meta === "object" && !Array.isArray(meta) ? meta : {};
|
|
12056
|
-
if (typeof
|
|
12478
|
+
const { name: name2, description, version, metadata } = meta && typeof meta === "object" && !Array.isArray(meta) ? meta : {};
|
|
12479
|
+
if (typeof name2 !== "string") throw bad("its front matter has no string name");
|
|
12057
12480
|
if (typeof description !== "string" || description.trim() === "") throw bad("its front matter has no string description");
|
|
12058
|
-
if (
|
|
12481
|
+
if (name2 !== ref.skill) throw bad(`its front matter names it "${printable(name2)}", but the index lists ${ref.skill}`);
|
|
12059
12482
|
const nested = metadata && typeof metadata === "object" ? metadata.version : void 0;
|
|
12060
12483
|
const v = printable(typeof version === "string" ? version : typeof nested === "string" ? nested : "");
|
|
12061
12484
|
return { description, ...v ? { version: v } : {} };
|
|
@@ -12226,8 +12649,8 @@ async function status(ctx) {
|
|
|
12226
12649
|
}
|
|
12227
12650
|
async function workspaceList(ctx) {
|
|
12228
12651
|
const { config } = ctx;
|
|
12229
|
-
const profiles = Object.entries(config.profiles).map(([
|
|
12230
|
-
name,
|
|
12652
|
+
const profiles = Object.entries(config.profiles).map(([name2, p]) => ({
|
|
12653
|
+
name: name2,
|
|
12231
12654
|
workspace: p.workspace,
|
|
12232
12655
|
email: p.email,
|
|
12233
12656
|
api_url: p.api_url
|
|
@@ -12239,14 +12662,14 @@ async function workspaceList(ctx) {
|
|
|
12239
12662
|
return EXIT.ok;
|
|
12240
12663
|
}
|
|
12241
12664
|
async function workspaceUse(ctx, args) {
|
|
12242
|
-
const
|
|
12243
|
-
if (!
|
|
12244
|
-
if (!ctx.config.profiles[
|
|
12245
|
-
throw usageError(`No profile named "${
|
|
12665
|
+
const name2 = args[0];
|
|
12666
|
+
if (!name2 || args.length > 1) throw usageError("Usage: amdahl workspace use <profile>");
|
|
12667
|
+
if (!ctx.config.profiles[name2]) {
|
|
12668
|
+
throw usageError(`No profile named "${name2}".`, `Run \`${amdahlCommand("workspace list")}\` to see your profiles.`);
|
|
12246
12669
|
}
|
|
12247
|
-
ctx.config.default_profile =
|
|
12670
|
+
ctx.config.default_profile = name2;
|
|
12248
12671
|
ctx.saveConfig();
|
|
12249
|
-
ctx.out.result({ ok: true, default:
|
|
12672
|
+
ctx.out.result({ ok: true, default: name2 }, `Default profile: ${name2}`);
|
|
12250
12673
|
return EXIT.ok;
|
|
12251
12674
|
}
|
|
12252
12675
|
|
|
@@ -12302,6 +12725,7 @@ With --json it prints the server's setup status as one object.
|
|
|
12302
12725
|
[--evidence off|workspace] [--on-unsupported flag|remove]
|
|
12303
12726
|
[--tries] [--context <file.json>]
|
|
12304
12727
|
amdahl optimize --list <file.csv|file.jsonl> [--no-wait] [--force]
|
|
12728
|
+
amdahl optimize --list <file.csv> --for <tool> [--channel email|linkedin]
|
|
12305
12729
|
amdahl optimize --batch <id> [--list <file>] [--force]
|
|
12306
12730
|
|
|
12307
12731
|
Rewrite an outbound email or LinkedIn message. Each file is one message; "-"
|
|
@@ -12323,12 +12747,29 @@ reads standard input. With no file, at a terminal, paste the message.
|
|
|
12323
12747
|
--no-wait With --list: queue the batch and print its id.
|
|
12324
12748
|
--batch <id> Pick up a batch queued earlier. With --list, the
|
|
12325
12749
|
same list; the results go next to it.
|
|
12750
|
+
--for <tool> With a CSV --list: also write the messages Amdahl
|
|
12751
|
+
wrote as a CSV that tool imports, next to the
|
|
12752
|
+
list (drafts.csv for lemlist gets
|
|
12753
|
+
drafts-lemlist.csv), then print how to import it.
|
|
12754
|
+
Tools: instantly, smartlead, lemlist, heyreach,
|
|
12755
|
+
reply_io, apollo, outreach, salesloft, hubspot,
|
|
12756
|
+
lgm, woodpecker, or other (any tool that imports
|
|
12757
|
+
a CSV).
|
|
12326
12758
|
--force Replace a results file that already exists.
|
|
12327
12759
|
|
|
12328
12760
|
In the results CSV, a cell that starts with =, +, - or @ gets a ' in front, so
|
|
12329
12761
|
a spreadsheet does not run it as a formula. That includes a phone number such
|
|
12330
12762
|
as +1 555 0100 or a negative number you copied through. Delete the ' to use it.
|
|
12331
12763
|
|
|
12764
|
+
The --for file holds only the leads Amdahl wrote, with your columns after
|
|
12765
|
+
Amdahl's, except the column the message came from and the ones Amdahl reads
|
|
12766
|
+
(message, channel, evidence, on_unsupported, facts, rules, item_id). Your tool
|
|
12767
|
+
imports a value as it is, so no cell gets the ' guard (the results file keeps
|
|
12768
|
+
it). A lead that failed, needed input or has no email (no LinkedIn URL for
|
|
12769
|
+
LinkedIn) is left out, and counted. A tool that takes one channel needs no
|
|
12770
|
+
--channel; lemlist, reply_io and other take both, so add --channel. With
|
|
12771
|
+
--json, .send_to has the file and the counts.
|
|
12772
|
+
|
|
12332
12773
|
Output: the rewrite goes to stdout. What Amdahl did, and the run id, go to
|
|
12333
12774
|
stderr. With --json it prints {"ok", "file", "result"}: the rewritten message
|
|
12334
12775
|
is .result.message and the run id is .result.run_id. Several files give an
|
|
@@ -12491,12 +12932,12 @@ var GROUPS = {
|
|
|
12491
12932
|
var ALIASES2 = { "auth login": "login", "auth logout": "logout", "auth status": "whoami" };
|
|
12492
12933
|
var HELP_COMMANDS = Object.keys(HELP);
|
|
12493
12934
|
function commandHelp(words) {
|
|
12494
|
-
const
|
|
12495
|
-
const text3 = HELP[
|
|
12935
|
+
const key2 = ALIASES2[words.join(" ")] ?? words.join(" ");
|
|
12936
|
+
const text3 = HELP[key2];
|
|
12496
12937
|
if (text3) return text3;
|
|
12497
12938
|
const group = words.length === 1 ? GROUPS[words[0] ?? ""] : void 0;
|
|
12498
12939
|
if (!group) return null;
|
|
12499
|
-
const lines = group.map((
|
|
12940
|
+
const lines = group.map((name2) => ` ${amdahlCommand(name2)}`);
|
|
12500
12941
|
return `Usage: amdahl ${words[0]} <command>
|
|
12501
12942
|
|
|
12502
12943
|
Commands:
|