yarkr-cli 0.1.0 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -4
- package/dist/yarkr.js +828 -855
- package/package.json +4 -5
package/dist/yarkr.js
CHANGED
|
@@ -1206,7 +1206,7 @@ var require_command = __commonJS({
|
|
|
1206
1206
|
"use strict";
|
|
1207
1207
|
var EventEmitter = __require("events").EventEmitter;
|
|
1208
1208
|
var childProcess = __require("child_process");
|
|
1209
|
-
var
|
|
1209
|
+
var path18 = __require("path");
|
|
1210
1210
|
var fs = __require("fs");
|
|
1211
1211
|
var process2 = __require("process");
|
|
1212
1212
|
var { Argument: Argument2, humanReadableArgName } = require_argument();
|
|
@@ -2219,9 +2219,9 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2219
2219
|
let launchWithNode = false;
|
|
2220
2220
|
const sourceExt = [".js", ".ts", ".tsx", ".mjs", ".cjs"];
|
|
2221
2221
|
function findFile(baseDir, baseName) {
|
|
2222
|
-
const localBin =
|
|
2222
|
+
const localBin = path18.resolve(baseDir, baseName);
|
|
2223
2223
|
if (fs.existsSync(localBin)) return localBin;
|
|
2224
|
-
if (sourceExt.includes(
|
|
2224
|
+
if (sourceExt.includes(path18.extname(baseName))) return void 0;
|
|
2225
2225
|
const foundExt = sourceExt.find(
|
|
2226
2226
|
(ext) => fs.existsSync(`${localBin}${ext}`)
|
|
2227
2227
|
);
|
|
@@ -2239,17 +2239,17 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2239
2239
|
} catch {
|
|
2240
2240
|
resolvedScriptPath = this._scriptPath;
|
|
2241
2241
|
}
|
|
2242
|
-
executableDir =
|
|
2243
|
-
|
|
2242
|
+
executableDir = path18.resolve(
|
|
2243
|
+
path18.dirname(resolvedScriptPath),
|
|
2244
2244
|
executableDir
|
|
2245
2245
|
);
|
|
2246
2246
|
}
|
|
2247
2247
|
if (executableDir) {
|
|
2248
2248
|
let localFile = findFile(executableDir, executableFile);
|
|
2249
2249
|
if (!localFile && !subcommand._executableFile && this._scriptPath) {
|
|
2250
|
-
const legacyName =
|
|
2250
|
+
const legacyName = path18.basename(
|
|
2251
2251
|
this._scriptPath,
|
|
2252
|
-
|
|
2252
|
+
path18.extname(this._scriptPath)
|
|
2253
2253
|
);
|
|
2254
2254
|
if (legacyName !== this._name) {
|
|
2255
2255
|
localFile = findFile(
|
|
@@ -2260,7 +2260,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2260
2260
|
}
|
|
2261
2261
|
executableFile = localFile || executableFile;
|
|
2262
2262
|
}
|
|
2263
|
-
launchWithNode = sourceExt.includes(
|
|
2263
|
+
launchWithNode = sourceExt.includes(path18.extname(executableFile));
|
|
2264
2264
|
let proc;
|
|
2265
2265
|
if (process2.platform !== "win32") {
|
|
2266
2266
|
if (launchWithNode) {
|
|
@@ -3175,7 +3175,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
3175
3175
|
* @return {Command}
|
|
3176
3176
|
*/
|
|
3177
3177
|
nameFromFilename(filename) {
|
|
3178
|
-
this._name =
|
|
3178
|
+
this._name = path18.basename(filename, path18.extname(filename));
|
|
3179
3179
|
return this;
|
|
3180
3180
|
}
|
|
3181
3181
|
/**
|
|
@@ -3189,9 +3189,9 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
3189
3189
|
* @param {string} [path]
|
|
3190
3190
|
* @return {(string|null|Command)}
|
|
3191
3191
|
*/
|
|
3192
|
-
executableDir(
|
|
3193
|
-
if (
|
|
3194
|
-
this._executableDir =
|
|
3192
|
+
executableDir(path19) {
|
|
3193
|
+
if (path19 === void 0) return this._executableDir;
|
|
3194
|
+
this._executableDir = path19;
|
|
3195
3195
|
return this;
|
|
3196
3196
|
}
|
|
3197
3197
|
/**
|
|
@@ -3547,17 +3547,17 @@ var require_visit = __commonJS({
|
|
|
3547
3547
|
visit2.BREAK = BREAK;
|
|
3548
3548
|
visit2.SKIP = SKIP2;
|
|
3549
3549
|
visit2.REMOVE = REMOVE;
|
|
3550
|
-
function visit_(key, node2, visitor,
|
|
3551
|
-
const ctrl = callVisitor(key, node2, visitor,
|
|
3550
|
+
function visit_(key, node2, visitor, path18) {
|
|
3551
|
+
const ctrl = callVisitor(key, node2, visitor, path18);
|
|
3552
3552
|
if (identity.isNode(ctrl) || identity.isPair(ctrl)) {
|
|
3553
|
-
replaceNode(key,
|
|
3554
|
-
return visit_(key, ctrl, visitor,
|
|
3553
|
+
replaceNode(key, path18, ctrl);
|
|
3554
|
+
return visit_(key, ctrl, visitor, path18);
|
|
3555
3555
|
}
|
|
3556
3556
|
if (typeof ctrl !== "symbol") {
|
|
3557
3557
|
if (identity.isCollection(node2)) {
|
|
3558
|
-
|
|
3558
|
+
path18 = Object.freeze(path18.concat(node2));
|
|
3559
3559
|
for (let i = 0; i < node2.items.length; ++i) {
|
|
3560
|
-
const ci = visit_(i, node2.items[i], visitor,
|
|
3560
|
+
const ci = visit_(i, node2.items[i], visitor, path18);
|
|
3561
3561
|
if (typeof ci === "number")
|
|
3562
3562
|
i = ci - 1;
|
|
3563
3563
|
else if (ci === BREAK)
|
|
@@ -3568,13 +3568,13 @@ var require_visit = __commonJS({
|
|
|
3568
3568
|
}
|
|
3569
3569
|
}
|
|
3570
3570
|
} else if (identity.isPair(node2)) {
|
|
3571
|
-
|
|
3572
|
-
const ck = visit_("key", node2.key, visitor,
|
|
3571
|
+
path18 = Object.freeze(path18.concat(node2));
|
|
3572
|
+
const ck = visit_("key", node2.key, visitor, path18);
|
|
3573
3573
|
if (ck === BREAK)
|
|
3574
3574
|
return BREAK;
|
|
3575
3575
|
else if (ck === REMOVE)
|
|
3576
3576
|
node2.key = null;
|
|
3577
|
-
const cv = visit_("value", node2.value, visitor,
|
|
3577
|
+
const cv = visit_("value", node2.value, visitor, path18);
|
|
3578
3578
|
if (cv === BREAK)
|
|
3579
3579
|
return BREAK;
|
|
3580
3580
|
else if (cv === REMOVE)
|
|
@@ -3595,17 +3595,17 @@ var require_visit = __commonJS({
|
|
|
3595
3595
|
visitAsync.BREAK = BREAK;
|
|
3596
3596
|
visitAsync.SKIP = SKIP2;
|
|
3597
3597
|
visitAsync.REMOVE = REMOVE;
|
|
3598
|
-
async function visitAsync_(key, node2, visitor,
|
|
3599
|
-
const ctrl = await callVisitor(key, node2, visitor,
|
|
3598
|
+
async function visitAsync_(key, node2, visitor, path18) {
|
|
3599
|
+
const ctrl = await callVisitor(key, node2, visitor, path18);
|
|
3600
3600
|
if (identity.isNode(ctrl) || identity.isPair(ctrl)) {
|
|
3601
|
-
replaceNode(key,
|
|
3602
|
-
return visitAsync_(key, ctrl, visitor,
|
|
3601
|
+
replaceNode(key, path18, ctrl);
|
|
3602
|
+
return visitAsync_(key, ctrl, visitor, path18);
|
|
3603
3603
|
}
|
|
3604
3604
|
if (typeof ctrl !== "symbol") {
|
|
3605
3605
|
if (identity.isCollection(node2)) {
|
|
3606
|
-
|
|
3606
|
+
path18 = Object.freeze(path18.concat(node2));
|
|
3607
3607
|
for (let i = 0; i < node2.items.length; ++i) {
|
|
3608
|
-
const ci = await visitAsync_(i, node2.items[i], visitor,
|
|
3608
|
+
const ci = await visitAsync_(i, node2.items[i], visitor, path18);
|
|
3609
3609
|
if (typeof ci === "number")
|
|
3610
3610
|
i = ci - 1;
|
|
3611
3611
|
else if (ci === BREAK)
|
|
@@ -3616,13 +3616,13 @@ var require_visit = __commonJS({
|
|
|
3616
3616
|
}
|
|
3617
3617
|
}
|
|
3618
3618
|
} else if (identity.isPair(node2)) {
|
|
3619
|
-
|
|
3620
|
-
const ck = await visitAsync_("key", node2.key, visitor,
|
|
3619
|
+
path18 = Object.freeze(path18.concat(node2));
|
|
3620
|
+
const ck = await visitAsync_("key", node2.key, visitor, path18);
|
|
3621
3621
|
if (ck === BREAK)
|
|
3622
3622
|
return BREAK;
|
|
3623
3623
|
else if (ck === REMOVE)
|
|
3624
3624
|
node2.key = null;
|
|
3625
|
-
const cv = await visitAsync_("value", node2.value, visitor,
|
|
3625
|
+
const cv = await visitAsync_("value", node2.value, visitor, path18);
|
|
3626
3626
|
if (cv === BREAK)
|
|
3627
3627
|
return BREAK;
|
|
3628
3628
|
else if (cv === REMOVE)
|
|
@@ -3649,23 +3649,23 @@ var require_visit = __commonJS({
|
|
|
3649
3649
|
}
|
|
3650
3650
|
return visitor;
|
|
3651
3651
|
}
|
|
3652
|
-
function callVisitor(key, node2, visitor,
|
|
3652
|
+
function callVisitor(key, node2, visitor, path18) {
|
|
3653
3653
|
if (typeof visitor === "function")
|
|
3654
|
-
return visitor(key, node2,
|
|
3654
|
+
return visitor(key, node2, path18);
|
|
3655
3655
|
if (identity.isMap(node2))
|
|
3656
|
-
return visitor.Map?.(key, node2,
|
|
3656
|
+
return visitor.Map?.(key, node2, path18);
|
|
3657
3657
|
if (identity.isSeq(node2))
|
|
3658
|
-
return visitor.Seq?.(key, node2,
|
|
3658
|
+
return visitor.Seq?.(key, node2, path18);
|
|
3659
3659
|
if (identity.isPair(node2))
|
|
3660
|
-
return visitor.Pair?.(key, node2,
|
|
3660
|
+
return visitor.Pair?.(key, node2, path18);
|
|
3661
3661
|
if (identity.isScalar(node2))
|
|
3662
|
-
return visitor.Scalar?.(key, node2,
|
|
3662
|
+
return visitor.Scalar?.(key, node2, path18);
|
|
3663
3663
|
if (identity.isAlias(node2))
|
|
3664
|
-
return visitor.Alias?.(key, node2,
|
|
3664
|
+
return visitor.Alias?.(key, node2, path18);
|
|
3665
3665
|
return void 0;
|
|
3666
3666
|
}
|
|
3667
|
-
function replaceNode(key,
|
|
3668
|
-
const parent =
|
|
3667
|
+
function replaceNode(key, path18, node2) {
|
|
3668
|
+
const parent = path18[path18.length - 1];
|
|
3669
3669
|
if (identity.isCollection(parent)) {
|
|
3670
3670
|
parent.items[key] = node2;
|
|
3671
3671
|
} else if (identity.isPair(parent)) {
|
|
@@ -4277,10 +4277,10 @@ var require_Collection = __commonJS({
|
|
|
4277
4277
|
var createNode = require_createNode();
|
|
4278
4278
|
var identity = require_identity();
|
|
4279
4279
|
var Node = require_Node();
|
|
4280
|
-
function collectionFromPath(schema,
|
|
4280
|
+
function collectionFromPath(schema, path18, value) {
|
|
4281
4281
|
let v = value;
|
|
4282
|
-
for (let i =
|
|
4283
|
-
const k =
|
|
4282
|
+
for (let i = path18.length - 1; i >= 0; --i) {
|
|
4283
|
+
const k = path18[i];
|
|
4284
4284
|
if (typeof k === "number" && Number.isInteger(k) && k >= 0) {
|
|
4285
4285
|
const a = [];
|
|
4286
4286
|
a[k] = v;
|
|
@@ -4299,7 +4299,7 @@ var require_Collection = __commonJS({
|
|
|
4299
4299
|
sourceObjects: /* @__PURE__ */ new Map()
|
|
4300
4300
|
});
|
|
4301
4301
|
}
|
|
4302
|
-
var isEmptyPath = (
|
|
4302
|
+
var isEmptyPath = (path18) => path18 == null || typeof path18 === "object" && !!path18[Symbol.iterator]().next().done;
|
|
4303
4303
|
var Collection = class extends Node.NodeBase {
|
|
4304
4304
|
constructor(type, schema) {
|
|
4305
4305
|
super(type);
|
|
@@ -4329,11 +4329,11 @@ var require_Collection = __commonJS({
|
|
|
4329
4329
|
* be a Pair instance or a `{ key, value }` object, which may not have a key
|
|
4330
4330
|
* that already exists in the map.
|
|
4331
4331
|
*/
|
|
4332
|
-
addIn(
|
|
4333
|
-
if (isEmptyPath(
|
|
4332
|
+
addIn(path18, value) {
|
|
4333
|
+
if (isEmptyPath(path18))
|
|
4334
4334
|
this.add(value);
|
|
4335
4335
|
else {
|
|
4336
|
-
const [key, ...rest] =
|
|
4336
|
+
const [key, ...rest] = path18;
|
|
4337
4337
|
const node2 = this.get(key, true);
|
|
4338
4338
|
if (identity.isCollection(node2))
|
|
4339
4339
|
node2.addIn(rest, value);
|
|
@@ -4347,8 +4347,8 @@ var require_Collection = __commonJS({
|
|
|
4347
4347
|
* Removes a value from the collection.
|
|
4348
4348
|
* @returns `true` if the item was found and removed.
|
|
4349
4349
|
*/
|
|
4350
|
-
deleteIn(
|
|
4351
|
-
const [key, ...rest] =
|
|
4350
|
+
deleteIn(path18) {
|
|
4351
|
+
const [key, ...rest] = path18;
|
|
4352
4352
|
if (rest.length === 0)
|
|
4353
4353
|
return this.delete(key);
|
|
4354
4354
|
const node2 = this.get(key, true);
|
|
@@ -4362,8 +4362,8 @@ var require_Collection = __commonJS({
|
|
|
4362
4362
|
* scalar values from their surrounding node; to disable set `keepScalar` to
|
|
4363
4363
|
* `true` (collections are always returned intact).
|
|
4364
4364
|
*/
|
|
4365
|
-
getIn(
|
|
4366
|
-
const [key, ...rest] =
|
|
4365
|
+
getIn(path18, keepScalar) {
|
|
4366
|
+
const [key, ...rest] = path18;
|
|
4367
4367
|
const node2 = this.get(key, true);
|
|
4368
4368
|
if (rest.length === 0)
|
|
4369
4369
|
return !keepScalar && identity.isScalar(node2) ? node2.value : node2;
|
|
@@ -4381,8 +4381,8 @@ var require_Collection = __commonJS({
|
|
|
4381
4381
|
/**
|
|
4382
4382
|
* Checks if the collection includes a value with the key `key`.
|
|
4383
4383
|
*/
|
|
4384
|
-
hasIn(
|
|
4385
|
-
const [key, ...rest] =
|
|
4384
|
+
hasIn(path18) {
|
|
4385
|
+
const [key, ...rest] = path18;
|
|
4386
4386
|
if (rest.length === 0)
|
|
4387
4387
|
return this.has(key);
|
|
4388
4388
|
const node2 = this.get(key, true);
|
|
@@ -4392,8 +4392,8 @@ var require_Collection = __commonJS({
|
|
|
4392
4392
|
* Sets a value in this collection. For `!!set`, `value` needs to be a
|
|
4393
4393
|
* boolean to add/remove the item from the set.
|
|
4394
4394
|
*/
|
|
4395
|
-
setIn(
|
|
4396
|
-
const [key, ...rest] =
|
|
4395
|
+
setIn(path18, value) {
|
|
4396
|
+
const [key, ...rest] = path18;
|
|
4397
4397
|
if (rest.length === 0) {
|
|
4398
4398
|
this.set(key, value);
|
|
4399
4399
|
} else {
|
|
@@ -6908,9 +6908,9 @@ var require_Document = __commonJS({
|
|
|
6908
6908
|
this.contents.add(value);
|
|
6909
6909
|
}
|
|
6910
6910
|
/** Adds a value to the document. */
|
|
6911
|
-
addIn(
|
|
6911
|
+
addIn(path18, value) {
|
|
6912
6912
|
if (assertCollection(this.contents))
|
|
6913
|
-
this.contents.addIn(
|
|
6913
|
+
this.contents.addIn(path18, value);
|
|
6914
6914
|
}
|
|
6915
6915
|
/**
|
|
6916
6916
|
* Create a new `Alias` node, ensuring that the target `node` has the required anchor.
|
|
@@ -6985,14 +6985,14 @@ var require_Document = __commonJS({
|
|
|
6985
6985
|
* Removes a value from the document.
|
|
6986
6986
|
* @returns `true` if the item was found and removed.
|
|
6987
6987
|
*/
|
|
6988
|
-
deleteIn(
|
|
6989
|
-
if (Collection.isEmptyPath(
|
|
6988
|
+
deleteIn(path18) {
|
|
6989
|
+
if (Collection.isEmptyPath(path18)) {
|
|
6990
6990
|
if (this.contents == null)
|
|
6991
6991
|
return false;
|
|
6992
6992
|
this.contents = null;
|
|
6993
6993
|
return true;
|
|
6994
6994
|
}
|
|
6995
|
-
return assertCollection(this.contents) ? this.contents.deleteIn(
|
|
6995
|
+
return assertCollection(this.contents) ? this.contents.deleteIn(path18) : false;
|
|
6996
6996
|
}
|
|
6997
6997
|
/**
|
|
6998
6998
|
* Returns item at `key`, or `undefined` if not found. By default unwraps
|
|
@@ -7007,10 +7007,10 @@ var require_Document = __commonJS({
|
|
|
7007
7007
|
* scalar values from their surrounding node; to disable set `keepScalar` to
|
|
7008
7008
|
* `true` (collections are always returned intact).
|
|
7009
7009
|
*/
|
|
7010
|
-
getIn(
|
|
7011
|
-
if (Collection.isEmptyPath(
|
|
7010
|
+
getIn(path18, keepScalar) {
|
|
7011
|
+
if (Collection.isEmptyPath(path18))
|
|
7012
7012
|
return !keepScalar && identity.isScalar(this.contents) ? this.contents.value : this.contents;
|
|
7013
|
-
return identity.isCollection(this.contents) ? this.contents.getIn(
|
|
7013
|
+
return identity.isCollection(this.contents) ? this.contents.getIn(path18, keepScalar) : void 0;
|
|
7014
7014
|
}
|
|
7015
7015
|
/**
|
|
7016
7016
|
* Checks if the document includes a value with the key `key`.
|
|
@@ -7021,10 +7021,10 @@ var require_Document = __commonJS({
|
|
|
7021
7021
|
/**
|
|
7022
7022
|
* Checks if the document includes a value at `path`.
|
|
7023
7023
|
*/
|
|
7024
|
-
hasIn(
|
|
7025
|
-
if (Collection.isEmptyPath(
|
|
7024
|
+
hasIn(path18) {
|
|
7025
|
+
if (Collection.isEmptyPath(path18))
|
|
7026
7026
|
return this.contents !== void 0;
|
|
7027
|
-
return identity.isCollection(this.contents) ? this.contents.hasIn(
|
|
7027
|
+
return identity.isCollection(this.contents) ? this.contents.hasIn(path18) : false;
|
|
7028
7028
|
}
|
|
7029
7029
|
/**
|
|
7030
7030
|
* Sets a value in this document. For `!!set`, `value` needs to be a
|
|
@@ -7041,13 +7041,13 @@ var require_Document = __commonJS({
|
|
|
7041
7041
|
* Sets a value in this document. For `!!set`, `value` needs to be a
|
|
7042
7042
|
* boolean to add/remove the item from the set.
|
|
7043
7043
|
*/
|
|
7044
|
-
setIn(
|
|
7045
|
-
if (Collection.isEmptyPath(
|
|
7044
|
+
setIn(path18, value) {
|
|
7045
|
+
if (Collection.isEmptyPath(path18)) {
|
|
7046
7046
|
this.contents = value;
|
|
7047
7047
|
} else if (this.contents == null) {
|
|
7048
|
-
this.contents = Collection.collectionFromPath(this.schema, Array.from(
|
|
7048
|
+
this.contents = Collection.collectionFromPath(this.schema, Array.from(path18), value);
|
|
7049
7049
|
} else if (assertCollection(this.contents)) {
|
|
7050
|
-
this.contents.setIn(
|
|
7050
|
+
this.contents.setIn(path18, value);
|
|
7051
7051
|
}
|
|
7052
7052
|
}
|
|
7053
7053
|
/**
|
|
@@ -9008,9 +9008,9 @@ var require_cst_visit = __commonJS({
|
|
|
9008
9008
|
visit2.BREAK = BREAK;
|
|
9009
9009
|
visit2.SKIP = SKIP2;
|
|
9010
9010
|
visit2.REMOVE = REMOVE;
|
|
9011
|
-
visit2.itemAtPath = (cst,
|
|
9011
|
+
visit2.itemAtPath = (cst, path18) => {
|
|
9012
9012
|
let item = cst;
|
|
9013
|
-
for (const [field, index2] of
|
|
9013
|
+
for (const [field, index2] of path18) {
|
|
9014
9014
|
const tok = item?.[field];
|
|
9015
9015
|
if (tok && "items" in tok) {
|
|
9016
9016
|
item = tok.items[index2];
|
|
@@ -9019,23 +9019,23 @@ var require_cst_visit = __commonJS({
|
|
|
9019
9019
|
}
|
|
9020
9020
|
return item;
|
|
9021
9021
|
};
|
|
9022
|
-
visit2.parentCollection = (cst,
|
|
9023
|
-
const parent = visit2.itemAtPath(cst,
|
|
9024
|
-
const field =
|
|
9022
|
+
visit2.parentCollection = (cst, path18) => {
|
|
9023
|
+
const parent = visit2.itemAtPath(cst, path18.slice(0, -1));
|
|
9024
|
+
const field = path18[path18.length - 1][0];
|
|
9025
9025
|
const coll = parent?.[field];
|
|
9026
9026
|
if (coll && "items" in coll)
|
|
9027
9027
|
return coll;
|
|
9028
9028
|
throw new Error("Parent collection not found");
|
|
9029
9029
|
};
|
|
9030
|
-
function _visit(
|
|
9031
|
-
let ctrl = visitor(item,
|
|
9030
|
+
function _visit(path18, item, visitor) {
|
|
9031
|
+
let ctrl = visitor(item, path18);
|
|
9032
9032
|
if (typeof ctrl === "symbol")
|
|
9033
9033
|
return ctrl;
|
|
9034
9034
|
for (const field of ["key", "value"]) {
|
|
9035
9035
|
const token = item[field];
|
|
9036
9036
|
if (token && "items" in token) {
|
|
9037
9037
|
for (let i = 0; i < token.items.length; ++i) {
|
|
9038
|
-
const ci = _visit(Object.freeze(
|
|
9038
|
+
const ci = _visit(Object.freeze(path18.concat([[field, i]])), token.items[i], visitor);
|
|
9039
9039
|
if (typeof ci === "number")
|
|
9040
9040
|
i = ci - 1;
|
|
9041
9041
|
else if (ci === BREAK)
|
|
@@ -9046,10 +9046,10 @@ var require_cst_visit = __commonJS({
|
|
|
9046
9046
|
}
|
|
9047
9047
|
}
|
|
9048
9048
|
if (typeof ctrl === "function" && field === "key")
|
|
9049
|
-
ctrl = ctrl(item,
|
|
9049
|
+
ctrl = ctrl(item, path18);
|
|
9050
9050
|
}
|
|
9051
9051
|
}
|
|
9052
|
-
return typeof ctrl === "function" ? ctrl(item,
|
|
9052
|
+
return typeof ctrl === "function" ? ctrl(item, path18) : ctrl;
|
|
9053
9053
|
}
|
|
9054
9054
|
exports.visit = visit2;
|
|
9055
9055
|
}
|
|
@@ -16023,8 +16023,8 @@ var require_utils = __commonJS({
|
|
|
16023
16023
|
}
|
|
16024
16024
|
return ind;
|
|
16025
16025
|
}
|
|
16026
|
-
function removeDotSegments(
|
|
16027
|
-
let input2 =
|
|
16026
|
+
function removeDotSegments(path18) {
|
|
16027
|
+
let input2 = path18;
|
|
16028
16028
|
const output3 = [];
|
|
16029
16029
|
let nextSlash = -1;
|
|
16030
16030
|
let len = 0;
|
|
@@ -16433,8 +16433,8 @@ var require_schemes = __commonJS({
|
|
|
16433
16433
|
}
|
|
16434
16434
|
if (wsComponent.resourceName) {
|
|
16435
16435
|
const queryIndex = wsComponent.resourceName.indexOf("?");
|
|
16436
|
-
const
|
|
16437
|
-
wsComponent.path =
|
|
16436
|
+
const path18 = queryIndex === -1 ? wsComponent.resourceName : wsComponent.resourceName.slice(0, queryIndex);
|
|
16437
|
+
wsComponent.path = path18 && path18 !== "/" ? path18 : void 0;
|
|
16438
16438
|
wsComponent.query = queryIndex === -1 ? void 0 : wsComponent.resourceName.slice(queryIndex + 1);
|
|
16439
16439
|
wsComponent.resourceName = void 0;
|
|
16440
16440
|
}
|
|
@@ -20476,10 +20476,10 @@ function mergeDefs(...defs) {
|
|
|
20476
20476
|
function cloneDef(schema) {
|
|
20477
20477
|
return mergeDefs(schema._zod.def);
|
|
20478
20478
|
}
|
|
20479
|
-
function getElementAtPath(obj,
|
|
20480
|
-
if (!
|
|
20479
|
+
function getElementAtPath(obj, path18) {
|
|
20480
|
+
if (!path18)
|
|
20481
20481
|
return obj;
|
|
20482
|
-
return
|
|
20482
|
+
return path18.reduce((acc, key) => acc?.[key], obj);
|
|
20483
20483
|
}
|
|
20484
20484
|
function promiseAllObject(promisesObj) {
|
|
20485
20485
|
const keys = Object.keys(promisesObj);
|
|
@@ -20819,11 +20819,11 @@ function explicitlyAborted(x, startIndex = 0) {
|
|
|
20819
20819
|
}
|
|
20820
20820
|
return false;
|
|
20821
20821
|
}
|
|
20822
|
-
function prefixIssues(
|
|
20822
|
+
function prefixIssues(path18, issues) {
|
|
20823
20823
|
return issues.map((iss) => {
|
|
20824
20824
|
var _a3;
|
|
20825
20825
|
(_a3 = iss).path ?? (_a3.path = []);
|
|
20826
|
-
iss.path.unshift(
|
|
20826
|
+
iss.path.unshift(path18);
|
|
20827
20827
|
return iss;
|
|
20828
20828
|
});
|
|
20829
20829
|
}
|
|
@@ -21273,16 +21273,16 @@ function flattenError(error62, mapper = (issue2) => issue2.message) {
|
|
|
21273
21273
|
}
|
|
21274
21274
|
function formatError(error62, mapper = (issue2) => issue2.message) {
|
|
21275
21275
|
const fieldErrors = { _errors: [] };
|
|
21276
|
-
const processError = (error63,
|
|
21276
|
+
const processError = (error63, path18 = []) => {
|
|
21277
21277
|
for (const issue2 of error63.issues) {
|
|
21278
21278
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
21279
|
-
issue2.errors.map((issues) => processError({ issues }, [...
|
|
21279
|
+
issue2.errors.map((issues) => processError({ issues }, [...path18, ...issue2.path]));
|
|
21280
21280
|
} else if (issue2.code === "invalid_key") {
|
|
21281
|
-
processError({ issues: issue2.issues }, [...
|
|
21281
|
+
processError({ issues: issue2.issues }, [...path18, ...issue2.path]);
|
|
21282
21282
|
} else if (issue2.code === "invalid_element") {
|
|
21283
|
-
processError({ issues: issue2.issues }, [...
|
|
21283
|
+
processError({ issues: issue2.issues }, [...path18, ...issue2.path]);
|
|
21284
21284
|
} else {
|
|
21285
|
-
const fullpath = [...
|
|
21285
|
+
const fullpath = [...path18, ...issue2.path];
|
|
21286
21286
|
if (fullpath.length === 0) {
|
|
21287
21287
|
fieldErrors._errors.push(mapper(issue2));
|
|
21288
21288
|
} else {
|
|
@@ -21321,17 +21321,17 @@ function formatError(error62, mapper = (issue2) => issue2.message) {
|
|
|
21321
21321
|
}
|
|
21322
21322
|
function treeifyError(error62, mapper = (issue2) => issue2.message) {
|
|
21323
21323
|
const result = { errors: [] };
|
|
21324
|
-
const processError = (error63,
|
|
21324
|
+
const processError = (error63, path18 = []) => {
|
|
21325
21325
|
var _a3;
|
|
21326
21326
|
for (const issue2 of error63.issues) {
|
|
21327
21327
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
21328
|
-
issue2.errors.map((issues) => processError({ issues }, [...
|
|
21328
|
+
issue2.errors.map((issues) => processError({ issues }, [...path18, ...issue2.path]));
|
|
21329
21329
|
} else if (issue2.code === "invalid_key") {
|
|
21330
|
-
processError({ issues: issue2.issues }, [...
|
|
21330
|
+
processError({ issues: issue2.issues }, [...path18, ...issue2.path]);
|
|
21331
21331
|
} else if (issue2.code === "invalid_element") {
|
|
21332
|
-
processError({ issues: issue2.issues }, [...
|
|
21332
|
+
processError({ issues: issue2.issues }, [...path18, ...issue2.path]);
|
|
21333
21333
|
} else {
|
|
21334
|
-
const fullpath = [...
|
|
21334
|
+
const fullpath = [...path18, ...issue2.path];
|
|
21335
21335
|
if (fullpath.length === 0) {
|
|
21336
21336
|
result.errors.push(mapper(issue2));
|
|
21337
21337
|
continue;
|
|
@@ -21370,8 +21370,8 @@ function treeifyError(error62, mapper = (issue2) => issue2.message) {
|
|
|
21370
21370
|
}
|
|
21371
21371
|
function toDotPath(_path) {
|
|
21372
21372
|
const segs = [];
|
|
21373
|
-
const
|
|
21374
|
-
for (const seg of
|
|
21373
|
+
const path18 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
|
|
21374
|
+
for (const seg of path18) {
|
|
21375
21375
|
if (typeof seg === "number")
|
|
21376
21376
|
segs.push(`[${seg}]`);
|
|
21377
21377
|
else if (typeof seg === "symbol")
|
|
@@ -38473,13 +38473,13 @@ function resolveRef(ref, ctx) {
|
|
|
38473
38473
|
if (!ref.startsWith("#")) {
|
|
38474
38474
|
throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
|
|
38475
38475
|
}
|
|
38476
|
-
const
|
|
38477
|
-
if (
|
|
38476
|
+
const path18 = ref.slice(1).split("/").filter(Boolean);
|
|
38477
|
+
if (path18.length === 0) {
|
|
38478
38478
|
return ctx.rootSchema;
|
|
38479
38479
|
}
|
|
38480
38480
|
const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
|
|
38481
|
-
if (
|
|
38482
|
-
const key =
|
|
38481
|
+
if (path18[0] === defsKey) {
|
|
38482
|
+
const key = path18[1] === void 0 ? void 0 : decodeJSONPointerSegment(path18[1]);
|
|
38483
38483
|
if (!key || !ctx.defs[key]) {
|
|
38484
38484
|
throw new Error(`Reference not found: ${ref}`);
|
|
38485
38485
|
}
|
|
@@ -39329,52 +39329,20 @@ function date4(params) {
|
|
|
39329
39329
|
}
|
|
39330
39330
|
|
|
39331
39331
|
// ../../packages/schema/dist/harness.js
|
|
39332
|
-
var HARNESS_IDS = [
|
|
39333
|
-
"claude-code",
|
|
39334
|
-
"claude-cowork",
|
|
39335
|
-
"codex",
|
|
39336
|
-
"opencode",
|
|
39337
|
-
"cursor",
|
|
39338
|
-
"openai-agents-sdk",
|
|
39339
|
-
"linear",
|
|
39340
|
-
"notion",
|
|
39341
|
-
"custom-http",
|
|
39342
|
-
"generic"
|
|
39343
|
-
];
|
|
39332
|
+
var HARNESS_IDS = ["claude-code", "codex", "opencode", "cursor", "generic"];
|
|
39344
39333
|
var HarnessId = external_exports.enum(HARNESS_IDS);
|
|
39334
|
+
var isHarnessId = (id) => HARNESS_IDS.includes(id);
|
|
39345
39335
|
var HARNESSES = {
|
|
39346
39336
|
"claude-code": { id: "claude-code", label: "Claude Code", delivery: ["native-folder", "mcp"], evalAdapter: "native" },
|
|
39347
|
-
"claude-cowork": {
|
|
39348
|
-
id: "claude-cowork",
|
|
39349
|
-
label: "Claude Cowork",
|
|
39350
|
-
delivery: ["native-folder", "mcp"],
|
|
39351
|
-
evalAdapter: "equivalent",
|
|
39352
|
-
notes: "Evaluated through the Claude Agent SDK; results are labelled harness-equivalent."
|
|
39353
|
-
},
|
|
39354
39337
|
codex: { id: "codex", label: "Codex", delivery: ["native-folder", "mcp"], evalAdapter: "native" },
|
|
39355
39338
|
opencode: { id: "opencode", label: "opencode", delivery: ["native-folder", "mcp"], evalAdapter: "native" },
|
|
39356
39339
|
cursor: { id: "cursor", label: "Cursor", delivery: ["native-folder", "mcp"], evalAdapter: "none" },
|
|
39357
|
-
"openai-agents-sdk": { id: "openai-agents-sdk", label: "OpenAI Agents SDK", delivery: ["native-folder"], evalAdapter: "none" },
|
|
39358
|
-
linear: {
|
|
39359
|
-
id: "linear",
|
|
39360
|
-
label: "Linear agents",
|
|
39361
|
-
delivery: ["export-bundle", "mcp"],
|
|
39362
|
-
evalAdapter: "none",
|
|
39363
|
-
notes: "Rendered as an instruction bundle for Linear agent guidance."
|
|
39364
|
-
},
|
|
39365
|
-
notion: {
|
|
39366
|
-
id: "notion",
|
|
39367
|
-
label: "Notion agents",
|
|
39368
|
-
delivery: ["export-bundle", "mcp"],
|
|
39369
|
-
evalAdapter: "none",
|
|
39370
|
-
notes: "Rendered as an instruction page for Notion agent instructions."
|
|
39371
|
-
},
|
|
39372
|
-
"custom-http": { id: "custom-http", label: "Custom HTTP", delivery: ["http", "mcp"], evalAdapter: "native" },
|
|
39373
39340
|
generic: { id: "generic", label: "Generic folder", delivery: ["native-folder"], evalAdapter: "none" }
|
|
39374
39341
|
};
|
|
39375
39342
|
|
|
39376
39343
|
// ../../packages/schema/dist/manifest.js
|
|
39377
39344
|
var MANIFEST_FILE = "yarkr.yaml";
|
|
39345
|
+
var INDEX_FILE = "yarkr.index.yaml";
|
|
39378
39346
|
var PackageKind = external_exports.enum(["skill", "agent", "toolset"]);
|
|
39379
39347
|
var Classification = external_exports.enum(["public", "internal", "restricted"]);
|
|
39380
39348
|
var PackageName = external_exports.string().regex(/^[a-z0-9][a-z0-9-]*\/[a-z0-9][a-z0-9-]*$/, "Use namespace/name in lowercase, e.g. finance/invoice-extraction");
|
|
@@ -39388,8 +39356,8 @@ var AgentSpec = external_exports.object({
|
|
|
39388
39356
|
tools: external_exports.array(external_exports.string()).default([]),
|
|
39389
39357
|
subagents: external_exports.array(PackageName).default([]),
|
|
39390
39358
|
parameters: external_exports.record(external_exports.string(), external_exports.unknown()).optional(),
|
|
39391
|
-
/** Per-harness overrides merged into the rendered output. */
|
|
39392
|
-
render: external_exports.
|
|
39359
|
+
/** Per-harness overrides merged into the rendered output, keyed by harness id; unknown harnesses are ignored. */
|
|
39360
|
+
render: external_exports.record(external_exports.string(), external_exports.record(external_exports.string(), external_exports.unknown())).optional()
|
|
39393
39361
|
});
|
|
39394
39362
|
var McpServerConfig = external_exports.object({
|
|
39395
39363
|
name: external_exports.string(),
|
|
@@ -39419,7 +39387,8 @@ var Manifest = external_exports.object({
|
|
|
39419
39387
|
version: SemVer,
|
|
39420
39388
|
description: external_exports.string().min(1).max(500),
|
|
39421
39389
|
owners: external_exports.array(Principal).min(1),
|
|
39422
|
-
|
|
39390
|
+
/** Harnesses this package is for. Ids this build doesn't know (another harness, or one Yarkr dropped) are ignored. */
|
|
39391
|
+
targets: external_exports.preprocess((v) => Array.isArray(v) ? v.filter((t) => typeof t !== "string" || isHarnessId(t)) : v, external_exports.array(HarnessId).min(1, "List at least one supported harness in targets")),
|
|
39423
39392
|
tags: external_exports.array(external_exports.string()).default([]),
|
|
39424
39393
|
depends: external_exports.object({
|
|
39425
39394
|
skills: DependencyMap.optional(),
|
|
@@ -39485,7 +39454,7 @@ var EvalSuite = external_exports.object({
|
|
|
39485
39454
|
cases: external_exports.array(EvalCase).min(1),
|
|
39486
39455
|
thresholds: Thresholds.default({ pass_rate: ">= baseline - 0.02", no_new_failures_on: ["critical"] })
|
|
39487
39456
|
});
|
|
39488
|
-
var EvalRunStatus = external_exports.enum(["
|
|
39457
|
+
var EvalRunStatus = external_exports.enum(["passed", "failed", "error"]);
|
|
39489
39458
|
var EvalMode = external_exports.enum(["smoke", "full"]);
|
|
39490
39459
|
|
|
39491
39460
|
// ../../packages/schema/dist/api.js
|
|
@@ -39513,7 +39482,7 @@ var PackageQuery = external_exports.object({
|
|
|
39513
39482
|
limit: external_exports.coerce.number().int().min(1).max(200).default(50),
|
|
39514
39483
|
offset: external_exports.coerce.number().int().min(0).default(0)
|
|
39515
39484
|
});
|
|
39516
|
-
var
|
|
39485
|
+
var YankBody = external_exports.object({ reason: external_exports.string().min(1).max(500) });
|
|
39517
39486
|
var ImportedTrial = external_exports.object({
|
|
39518
39487
|
suite: external_exports.string(),
|
|
39519
39488
|
case_id: external_exports.string(),
|
|
@@ -39546,14 +39515,16 @@ var EvalImportBody = external_exports.object({
|
|
|
39546
39515
|
});
|
|
39547
39516
|
var ConnectRepoBody = external_exports.object({
|
|
39548
39517
|
connected: external_exports.boolean().default(true),
|
|
39549
|
-
/** Defaults to the org slug. Created in the org when it doesn't exist yet. */
|
|
39550
|
-
namespace: external_exports.string().regex(/^[a-z0-9][a-z0-9-]*$/).optional(),
|
|
39551
39518
|
/** Defaults: `public` for public repos, `restricted` for private ones. Public repos are always `public`. */
|
|
39552
39519
|
classification: Classification.optional(),
|
|
39553
39520
|
root_path: external_exports.string().max(200).optional()
|
|
39554
39521
|
});
|
|
39555
39522
|
var AuditQuery = external_exports.object({
|
|
39556
39523
|
package: external_exports.string().optional(),
|
|
39524
|
+
/** `me`: only what you did yourself. Anyone may read their own events. */
|
|
39525
|
+
actor: external_exports.literal("me").optional(),
|
|
39526
|
+
/** An org slug: its members, arks, repos and packages. For that org's admins. */
|
|
39527
|
+
org: external_exports.string().optional(),
|
|
39557
39528
|
action: external_exports.string().optional(),
|
|
39558
39529
|
from: external_exports.string().datetime().optional(),
|
|
39559
39530
|
to: external_exports.string().datetime().optional(),
|
|
@@ -39569,18 +39540,11 @@ var CreateUserBody = external_exports.object({
|
|
|
39569
39540
|
});
|
|
39570
39541
|
var OrgRole = external_exports.enum(["member", "admin"]);
|
|
39571
39542
|
var Slug = external_exports.string().regex(/^[a-z0-9][a-z0-9-]*$/, "Use lowercase letters, digits and dashes");
|
|
39572
|
-
var CreateOrgNamespaceBody = external_exports.object({
|
|
39573
|
-
name: external_exports.string().regex(/^[a-z0-9][a-z0-9-]*$/).max(64),
|
|
39574
|
-
description: external_exports.string().max(500).default("")
|
|
39575
|
-
});
|
|
39576
39543
|
var CreateOrgBody = external_exports.object({
|
|
39577
|
-
slug: Slug
|
|
39544
|
+
slug: Slug,
|
|
39578
39545
|
name: external_exports.string().min(1).max(120)
|
|
39579
39546
|
});
|
|
39580
|
-
var UpdateOrgBody = external_exports.object({
|
|
39581
|
-
name: external_exports.string().min(1).max(120).optional(),
|
|
39582
|
-
allow_personal_additions: external_exports.boolean().optional()
|
|
39583
|
-
});
|
|
39547
|
+
var UpdateOrgBody = external_exports.object({ name: external_exports.string().min(1).max(120).optional() });
|
|
39584
39548
|
var OrgMemberBody = external_exports.object({ email: external_exports.string().email(), role: OrgRole.default("member") });
|
|
39585
39549
|
var ArkServerOverride = external_exports.object({
|
|
39586
39550
|
env: external_exports.record(external_exports.string(), external_exports.string()).optional(),
|
|
@@ -39591,13 +39555,11 @@ var ArkServerOverride = external_exports.object({
|
|
|
39591
39555
|
var ArkItemConfig = external_exports.object({ servers: external_exports.record(external_exports.string(), ArkServerOverride).optional() });
|
|
39592
39556
|
var CreateArkBody = external_exports.object({
|
|
39593
39557
|
name: Slug,
|
|
39594
|
-
description: external_exports.string().max(500).default("")
|
|
39595
|
-
idp_group: external_exports.string().nullable().optional()
|
|
39558
|
+
description: external_exports.string().max(500).default("")
|
|
39596
39559
|
});
|
|
39597
39560
|
var UpdateArkBody = external_exports.object({
|
|
39598
39561
|
description: external_exports.string().max(500).optional(),
|
|
39599
|
-
|
|
39600
|
-
/** Public arks are visible to everyone and can go into anyone's collection. They may only hold public packages. */
|
|
39562
|
+
/** Anyone can see and use a public ark, signed in or not. It may only hold public packages. */
|
|
39601
39563
|
public: external_exports.boolean().optional()
|
|
39602
39564
|
});
|
|
39603
39565
|
var ArkItemBody = external_exports.object({
|
|
@@ -39612,30 +39574,14 @@ var EffectiveArkQuery = external_exports.object({
|
|
|
39612
39574
|
/** Comma-separated ark refs to narrow to; omit for all. */
|
|
39613
39575
|
arks: external_exports.string().optional()
|
|
39614
39576
|
});
|
|
39615
|
-
var
|
|
39616
|
-
var COLLECTION_REF = /^@([a-z0-9][a-z0-9-]*)\/([a-z0-9][a-z0-9-]*)(?:@([1-9][0-9]*))?$/;
|
|
39617
|
-
function parseCollectionRef(ref) {
|
|
39618
|
-
const m = COLLECTION_REF.exec(ref);
|
|
39619
|
-
return m ? { handle: m[1], name: m[2], version: m[3] ? Number(m[3]) : null } : null;
|
|
39620
|
-
}
|
|
39621
|
-
var CreateCollectionBody = external_exports.object({
|
|
39622
|
-
name: Slug,
|
|
39623
|
-
description: external_exports.string().max(500).default(""),
|
|
39624
|
-
visibility: CollectionVisibility.default("private"),
|
|
39625
|
-
/** Required for `org` visibility: the org whose members may use it. */
|
|
39626
|
-
org: external_exports.string().optional()
|
|
39627
|
-
});
|
|
39628
|
-
var UpdateCollectionBody = external_exports.object({
|
|
39629
|
-
description: external_exports.string().max(500).optional(),
|
|
39630
|
-
visibility: CollectionVisibility.optional(),
|
|
39631
|
-
org: external_exports.string().optional()
|
|
39632
|
-
});
|
|
39633
|
-
var CollectionArkBody = external_exports.object({ ark: external_exports.string().min(1) });
|
|
39634
|
-
var PublishCollectionBody = external_exports.object({ note: external_exports.string().max(500).default("") });
|
|
39635
|
-
var PersonalItemBody = external_exports.object({ package: PackageName, range: external_exports.string().nullable().optional() });
|
|
39577
|
+
var PersonalItemBody = external_exports.object({ package: PackageName, range: external_exports.string().nullable().optional(), channel: external_exports.string().nullable().optional() });
|
|
39636
39578
|
var ExclusionBody = external_exports.object({ ark: external_exports.string(), package: PackageName });
|
|
39637
39579
|
|
|
39638
39580
|
// src/commands/auth.ts
|
|
39581
|
+
import { spawn } from "child_process";
|
|
39582
|
+
import { randomBytes } from "crypto";
|
|
39583
|
+
import { createServer } from "http";
|
|
39584
|
+
import os3 from "os";
|
|
39639
39585
|
import { createInterface } from "readline/promises";
|
|
39640
39586
|
import path3 from "path";
|
|
39641
39587
|
import { Writable } from "stream";
|
|
@@ -39797,8 +39743,8 @@ var Api = class {
|
|
|
39797
39743
|
this.conn = conn;
|
|
39798
39744
|
}
|
|
39799
39745
|
conn;
|
|
39800
|
-
async request(method,
|
|
39801
|
-
const url2 = `${this.conn.server}/api/v1${
|
|
39746
|
+
async request(method, path18, body, { allow404 = false } = {}) {
|
|
39747
|
+
const url2 = `${this.conn.server}/api/v1${path18}`;
|
|
39802
39748
|
let res;
|
|
39803
39749
|
try {
|
|
39804
39750
|
res = await fetch(url2, {
|
|
@@ -39820,7 +39766,7 @@ var Api = class {
|
|
|
39820
39766
|
payload = await res.json();
|
|
39821
39767
|
} catch {
|
|
39822
39768
|
}
|
|
39823
|
-
const msg = payload.message ?? `${method} ${
|
|
39769
|
+
const msg = payload.message ?? `${method} ${path18} failed with HTTP ${res.status}.`;
|
|
39824
39770
|
if (res.status === 401) {
|
|
39825
39771
|
throw new CliError(
|
|
39826
39772
|
msg,
|
|
@@ -39835,6 +39781,8 @@ ${JSON.stringify(payload.details, null, 2)}` : "";
|
|
|
39835
39781
|
}
|
|
39836
39782
|
info = () => this.request("GET", "/info");
|
|
39837
39783
|
me = () => this.request("GET", "/me");
|
|
39784
|
+
/** Revokes the token this client is using (`yarkr logout`). */
|
|
39785
|
+
revokeCurrentToken = () => this.request("DELETE", "/tokens/current");
|
|
39838
39786
|
search = (q) => {
|
|
39839
39787
|
const qs = new URLSearchParams(Object.entries(q).filter((e) => !!e[1])).toString();
|
|
39840
39788
|
return this.request("GET", `/packages${qs ? `?${qs}` : ""}`);
|
|
@@ -39845,23 +39793,22 @@ ${JSON.stringify(payload.details, null, 2)}` : "";
|
|
|
39845
39793
|
const qs = new URLSearchParams({ channel: opts.channel, ...opts.range ? { range: opts.range } : {} });
|
|
39846
39794
|
return this.request("GET", `/packages/${split(name)}/resolve?${qs}`);
|
|
39847
39795
|
};
|
|
39848
|
-
|
|
39796
|
+
/** A whole release. `sync` marks a fetch that installs it, which the hub counts as a download. */
|
|
39797
|
+
bundle = (name, version2, { sync: sync2 = false } = {}) => this.request("GET", `/packages/${split(name)}/releases/${encodeURIComponent(version2)}/bundle${sync2 ? "?use=sync" : ""}`);
|
|
39849
39798
|
signingKey = () => this.request("GET", "/signing-key", void 0, { allow404: true });
|
|
39850
|
-
/** The caller's effective set:
|
|
39799
|
+
/** The caller's effective set: org arks ∪ personal ark. `only` narrows to some ark refs. */
|
|
39851
39800
|
myArk = (only) => this.request("GET", `/me/ark${only?.length ? `?arks=${encodeURIComponent(only.join(","))}` : ""}`);
|
|
39852
|
-
|
|
39853
|
-
|
|
39854
|
-
|
|
39855
|
-
|
|
39856
|
-
|
|
39857
|
-
|
|
39858
|
-
|
|
39859
|
-
|
|
39860
|
-
/** A published collection version by ref: `@ana/pdf` (latest) or `@ana/pdf@3`. Works without a token for public ones. */
|
|
39861
|
-
readCollection = (ref) => {
|
|
39862
|
-
const [handle, rest] = [ref.slice(0, ref.indexOf("/")), ref.slice(ref.indexOf("/") + 1)];
|
|
39863
|
-
return this.request("GET", `/collections/${encodeURIComponent(handle)}/${encodeURIComponent(rest)}`);
|
|
39801
|
+
/**
|
|
39802
|
+
* One ark by ref (`<org>/<ark>`): yours, or a public one, which works without a token. `sync` marks a fetch that
|
|
39803
|
+
* installs it, which the hub counts to rank public arks.
|
|
39804
|
+
*/
|
|
39805
|
+
ark = (ref, { sync: sync2 = false } = {}) => {
|
|
39806
|
+
const [org, name, extra] = ref.split("/");
|
|
39807
|
+
if (!org || !name || extra !== void 0 || ref.startsWith("@")) throw new CliError(`"${ref}" isn't an ark.`, "Arks look like <org>/<ark>, e.g. acme/finance; @me is your personal ark.");
|
|
39808
|
+
return this.request("GET", `/arks/${encodeURIComponent(org)}/${encodeURIComponent(name)}${sync2 ? "?use=sync" : ""}`);
|
|
39864
39809
|
};
|
|
39810
|
+
/** Yank a release (org admins), or undo it with `reason: null`. */
|
|
39811
|
+
yank = (name, version2, reason) => this.request(reason === null ? "DELETE" : "POST", `/packages/${split(name)}/releases/${encodeURIComponent(version2)}/yank`, reason === null ? void 0 : { reason });
|
|
39865
39812
|
publicArks = () => this.request("GET", "/arks/public");
|
|
39866
39813
|
addPersonal = (name, range) => this.request("POST", "/me/ark/items", { package: name, range: range ?? null });
|
|
39867
39814
|
removePersonal = (name) => this.request("DELETE", `/me/ark/items/${split(name)}`);
|
|
@@ -39910,17 +39857,17 @@ function parseManifest(text) {
|
|
|
39910
39857
|
}
|
|
39911
39858
|
return manifest;
|
|
39912
39859
|
}
|
|
39913
|
-
function parseEvalSuite(text,
|
|
39860
|
+
function parseEvalSuite(text, path18 = "suite") {
|
|
39914
39861
|
let raw;
|
|
39915
39862
|
try {
|
|
39916
39863
|
raw = import_yaml.default.parse(text);
|
|
39917
39864
|
} catch (err) {
|
|
39918
|
-
throw new ManifestError(`${
|
|
39865
|
+
throw new ManifestError(`${path18} is not valid YAML: ${err.message}`);
|
|
39919
39866
|
}
|
|
39920
39867
|
const res = EvalSuite.safeParse(raw);
|
|
39921
39868
|
if (!res.success) {
|
|
39922
39869
|
const issues = res.error.issues.map((i) => ({ path: i.path.join("."), message: i.message }));
|
|
39923
|
-
throw new ManifestError(`${
|
|
39870
|
+
throw new ManifestError(`${path18} is invalid: ${issues.map((i) => `${i.path}: ${i.message}`).join("; ")}`, issues);
|
|
39924
39871
|
}
|
|
39925
39872
|
return res.data;
|
|
39926
39873
|
}
|
|
@@ -39977,8 +39924,8 @@ function asText(content) {
|
|
|
39977
39924
|
return null;
|
|
39978
39925
|
return typeof content === "string" ? content : new TextDecoder().decode(content);
|
|
39979
39926
|
}
|
|
39980
|
-
function isYarkrOnly(
|
|
39981
|
-
return
|
|
39927
|
+
function isYarkrOnly(path18) {
|
|
39928
|
+
return path18 === MANIFEST_FILE || path18 === INDEX_FILE || path18.startsWith("evals/") || path18.startsWith("fixtures/");
|
|
39982
39929
|
}
|
|
39983
39930
|
function skillEntryPath(m) {
|
|
39984
39931
|
return m.entry ?? "SKILL.md";
|
|
@@ -40006,10 +39953,10 @@ ${body.replace(/^\n+/, "")}`);
|
|
|
40006
39953
|
function skillFolderFiles(pkg, dir, folderName) {
|
|
40007
39954
|
const entry = skillEntryPath(pkg.manifest);
|
|
40008
39955
|
const files = [{ package: pkg.manifest.name, path: join(dir, folderName, "SKILL.md"), content: renderSkillMd(pkg, folderName) }];
|
|
40009
|
-
for (const [
|
|
40010
|
-
if (
|
|
39956
|
+
for (const [path18, content] of Object.entries(pkg.files)) {
|
|
39957
|
+
if (path18 === entry || path18 === "SKILL.md" || isYarkrOnly(path18))
|
|
40011
39958
|
continue;
|
|
40012
|
-
files.push({ package: pkg.manifest.name, path: join(dir, folderName,
|
|
39959
|
+
files.push({ package: pkg.manifest.name, path: join(dir, folderName, path18), content });
|
|
40013
39960
|
}
|
|
40014
39961
|
return files;
|
|
40015
39962
|
}
|
|
@@ -40078,20 +40025,6 @@ function standardMcpEntry(pkg, s, style, notes, withType) {
|
|
|
40078
40025
|
function clean(o) {
|
|
40079
40026
|
return Object.fromEntries(Object.entries(o).filter(([, v]) => v !== void 0));
|
|
40080
40027
|
}
|
|
40081
|
-
function inlineMarkdown(pkg, skip) {
|
|
40082
|
-
const parts = [];
|
|
40083
|
-
for (const [path16, content] of Object.entries(pkg.files).sort(([a], [b]) => a < b ? -1 : 1)) {
|
|
40084
|
-
if (skip.has(path16) || isYarkrOnly(path16) || !/\.(md|markdown|txt)$/i.test(path16))
|
|
40085
|
-
continue;
|
|
40086
|
-
const text = asText(content);
|
|
40087
|
-
if (text === null)
|
|
40088
|
-
continue;
|
|
40089
|
-
parts.push(`### Reference: ${path16}
|
|
40090
|
-
|
|
40091
|
-
${splitFrontmatter(text).body.trim()}`);
|
|
40092
|
-
}
|
|
40093
|
-
return parts.join("\n\n");
|
|
40094
|
-
}
|
|
40095
40028
|
|
|
40096
40029
|
// ../../packages/core/dist/harnesses/types.js
|
|
40097
40030
|
function defineHarness(def) {
|
|
@@ -40117,13 +40050,13 @@ function nativeFolderHarness(o) {
|
|
|
40117
40050
|
...o.mcp ? {
|
|
40118
40051
|
toolsets(servers, ctx) {
|
|
40119
40052
|
const mcp = o.mcp;
|
|
40120
|
-
const
|
|
40121
|
-
if (!
|
|
40053
|
+
const path18 = ctx.layout[slot];
|
|
40054
|
+
if (!path18) {
|
|
40122
40055
|
if (mcp.unavailable)
|
|
40123
40056
|
ctx.out.notes.push(mcp.unavailable(servers));
|
|
40124
40057
|
return;
|
|
40125
40058
|
}
|
|
40126
|
-
ctx.out.mcp.push({ path:
|
|
40059
|
+
ctx.out.mcp.push({ path: path18, key: mcp.key, servers: Object.fromEntries(servers.map(({ pkg, server }) => [server.name, mcp.entry(pkg, server, ctx.out.notes)])) });
|
|
40127
40060
|
}
|
|
40128
40061
|
} : {}
|
|
40129
40062
|
});
|
|
@@ -40165,68 +40098,6 @@ function claudeMcpJson(mcpUrl, tokenEnv) {
|
|
|
40165
40098
|
return JSON.stringify({ mcpServers: { yarkr: { type: "http", url: mcpUrl, headers: { Authorization: `Bearer \${${tokenEnv}}` } } } }, null, 2);
|
|
40166
40099
|
}
|
|
40167
40100
|
|
|
40168
|
-
// ../../packages/core/dist/harnesses/claude-cowork.js
|
|
40169
|
-
var claudeCowork = defineHarness({
|
|
40170
|
-
id: "claude-cowork",
|
|
40171
|
-
layout: {
|
|
40172
|
-
project: { plugin: "yarkr/exports/claude-cowork/yarkr", name: "yarkr" },
|
|
40173
|
-
user: { plugin: ".yarkr/exports/claude-cowork/yarkr", name: "yarkr" }
|
|
40174
|
-
},
|
|
40175
|
-
skill(pkg, ctx) {
|
|
40176
|
-
ctx.out.files.push(...skillFolderFiles(pkg, join(ctx.layout.plugin, "skills"), ctx.names.get(pkg.manifest.name)));
|
|
40177
|
-
},
|
|
40178
|
-
agent(pkg, ctx) {
|
|
40179
|
-
const parts = agentParts(pkg, ctx.harness, ctx.names, ctx.out);
|
|
40180
|
-
const fm = { ...claudeAgentFrontmatter(pkg, parts, ctx), ...parts.overrides };
|
|
40181
|
-
ctx.out.files.push({ package: pkg.manifest.name, path: join(ctx.layout.plugin, "agents", `${ctx.names.get(pkg.manifest.name)}.md`), content: agentMarkdown(pkg, fm, parts) });
|
|
40182
|
-
},
|
|
40183
|
-
toolsets(servers, ctx) {
|
|
40184
|
-
ctx.out.files.push({
|
|
40185
|
-
path: join(ctx.layout.plugin, ".mcp.json"),
|
|
40186
|
-
content: JSON.stringify({ mcpServers: Object.fromEntries(servers.map(({ pkg, server }) => [server.name, standardMcpEntry(pkg, server, "dollar-brace", ctx.out.notes, true)])) }, null, 2) + "\n"
|
|
40187
|
-
});
|
|
40188
|
-
},
|
|
40189
|
-
finalize({ out, layout: l, input: input2 }) {
|
|
40190
|
-
if (!out.files.length)
|
|
40191
|
-
return;
|
|
40192
|
-
const root = l.plugin;
|
|
40193
|
-
out.files.push({
|
|
40194
|
-
path: join(root, ".claude-plugin", "plugin.json"),
|
|
40195
|
-
content: JSON.stringify({
|
|
40196
|
-
name: l.name,
|
|
40197
|
-
version: pluginVersion(input2),
|
|
40198
|
-
description: "Skills and agents from your Yarkr registry (managed by yarkr).",
|
|
40199
|
-
author: { name: "Yarkr" }
|
|
40200
|
-
}, null, 2) + "\n"
|
|
40201
|
-
});
|
|
40202
|
-
out.files.push({
|
|
40203
|
-
path: join(root, "README.md"),
|
|
40204
|
-
content: withFrontmatter({ "managed-by": "yarkr" }, `# Yarkr plugin for Claude Cowork
|
|
40205
|
-
|
|
40206
|
-
This folder is a Cowork plugin generated by \`yarkr sync\`.
|
|
40207
|
-
|
|
40208
|
-
1. Zip this folder (\`${l.name}\`).
|
|
40209
|
-
2. In Claude Cowork, open Customize \u2192 Plugins and upload the zip, or publish it to your organisation's plugin marketplace.
|
|
40210
|
-
3. Re-run \`yarkr sync\` and re-upload after updates.
|
|
40211
|
-
`)
|
|
40212
|
-
});
|
|
40213
|
-
out.notes.push(`Cowork plugin written to ${root}/. Zip and upload it in Cowork (Customize \u2192 Plugins).`);
|
|
40214
|
-
},
|
|
40215
|
-
mcpSnippet: (mcpUrl, tokenEnv, notes) => ({
|
|
40216
|
-
file: "Cowork: Customize \u2192 Connectors \u2192 Add custom connector",
|
|
40217
|
-
format: "json",
|
|
40218
|
-
content: claudeMcpJson(mcpUrl, tokenEnv),
|
|
40219
|
-
notes: [...notes, "Cowork custom connectors take the URL and an Authorization header; paste the token value there."]
|
|
40220
|
-
})
|
|
40221
|
-
});
|
|
40222
|
-
function pluginVersion(input2) {
|
|
40223
|
-
const key = input2.packages.map((p) => `${p.manifest.name}@${p.manifest.version}`).sort().join(",");
|
|
40224
|
-
let h = 0;
|
|
40225
|
-
for (let i = 0; i < key.length; i++)
|
|
40226
|
-
h = h * 31 + key.charCodeAt(i) >>> 0;
|
|
40227
|
-
return `0.0.${h % 1e5}`;
|
|
40228
|
-
}
|
|
40229
|
-
|
|
40230
40101
|
// ../../packages/core/dist/harnesses/codex.js
|
|
40231
40102
|
var index = /* @__PURE__ */ new WeakMap();
|
|
40232
40103
|
var indexOf = (ctx) => index.get(ctx) ?? index.set(ctx, []).get(ctx);
|
|
@@ -40370,10 +40241,10 @@ var cursor = defineHarness({
|
|
|
40370
40241
|
const entry = skillEntryPath(pkg.manifest);
|
|
40371
40242
|
const { data, body } = splitFrontmatter(asText(pkg.files[entry]) ?? "");
|
|
40372
40243
|
const extra = [];
|
|
40373
|
-
for (const [
|
|
40374
|
-
if (
|
|
40244
|
+
for (const [path18, content] of Object.entries(pkg.files)) {
|
|
40245
|
+
if (path18 === entry || isYarkrOnly(path18))
|
|
40375
40246
|
continue;
|
|
40376
|
-
const p = join(l.assets, name,
|
|
40247
|
+
const p = join(l.assets, name, path18);
|
|
40377
40248
|
ctx.out.files.push({ package: pkg.manifest.name, path: p, content });
|
|
40378
40249
|
extra.push(`- \`${p}\``);
|
|
40379
40250
|
}
|
|
@@ -40444,9 +40315,9 @@ function folderExportHarness(id, rootDefault, opts = {}) {
|
|
|
40444
40315
|
for (const pkg of byKind(input2, "agent")) {
|
|
40445
40316
|
const name = names.get(pkg.manifest.name);
|
|
40446
40317
|
const parts = agentParts(pkg, id, names, out);
|
|
40447
|
-
for (const [
|
|
40448
|
-
if (!isYarkrOnly(
|
|
40449
|
-
out.files.push({ package: pkg.manifest.name, path: join(root, "agents", name,
|
|
40318
|
+
for (const [path18, content] of Object.entries(pkg.files))
|
|
40319
|
+
if (!isYarkrOnly(path18))
|
|
40320
|
+
out.files.push({ package: pkg.manifest.name, path: join(root, "agents", name, path18), content });
|
|
40450
40321
|
index2.push({ kind: "agent", name, package: pkg.manifest.name, version: pkg.manifest.version, description: pkg.manifest.description, model: parts.model, tools: parts.tools, skills: parts.skills, subagents: parts.subagents, system_prompt: join("agents", name, pkg.manifest.agent?.system_prompt ?? "") });
|
|
40451
40322
|
}
|
|
40452
40323
|
for (const pkg of byKind(input2, "toolset")) {
|
|
@@ -40466,170 +40337,6 @@ function folderExportHarness(id, rootDefault, opts = {}) {
|
|
|
40466
40337
|
}
|
|
40467
40338
|
var generic = folderExportHarness("generic", "yarkr/generic", { acceptsAllTargets: true });
|
|
40468
40339
|
|
|
40469
|
-
// ../../packages/core/dist/harnesses/custom-http.js
|
|
40470
|
-
var customHttp = folderExportHarness("custom-http", "yarkr/custom-http");
|
|
40471
|
-
|
|
40472
|
-
// ../../packages/core/dist/harnesses/workspace.js
|
|
40473
|
-
function workspaceHarness(t) {
|
|
40474
|
-
return defineHarness({
|
|
40475
|
-
id: t.id,
|
|
40476
|
-
layout: {
|
|
40477
|
-
project: { root: `yarkr/exports/${t.id}` },
|
|
40478
|
-
user: { root: `.yarkr/exports/${t.id}` }
|
|
40479
|
-
},
|
|
40480
|
-
render({ input: input2, layout, names, out }) {
|
|
40481
|
-
const root = layout.root;
|
|
40482
|
-
const byName = new Map(input2.packages.map((p) => [p.manifest.name, p]));
|
|
40483
|
-
const rows = [];
|
|
40484
|
-
const header = (p) => `<!-- managed by yarkr: ${p.manifest.name}@${p.manifest.version}. Regenerate with \`yarkr sync\`; change it with a pull request in its repo. -->`;
|
|
40485
|
-
for (const pkg of byKind(input2, "skill")) {
|
|
40486
|
-
const name = names.get(pkg.manifest.name);
|
|
40487
|
-
const entry = skillEntryPath(pkg.manifest);
|
|
40488
|
-
const body = splitFrontmatter(asText(pkg.files[entry]) ?? "").body.trim();
|
|
40489
|
-
const refs = inlineMarkdown(pkg, /* @__PURE__ */ new Set([entry]));
|
|
40490
|
-
out.files.push({
|
|
40491
|
-
package: pkg.manifest.name,
|
|
40492
|
-
path: join(root, `${name}.md`),
|
|
40493
|
-
content: `${header(pkg)}
|
|
40494
|
-
|
|
40495
|
-
# ${name}
|
|
40496
|
-
|
|
40497
|
-
Use when: ${pkg.manifest.description}
|
|
40498
|
-
|
|
40499
|
-
${body}${refs ? `
|
|
40500
|
-
|
|
40501
|
-
${refs}` : ""}
|
|
40502
|
-
`
|
|
40503
|
-
});
|
|
40504
|
-
rows.push(`| \`${name}.md\` | skill | ${pkg.manifest.name}@${pkg.manifest.version} | ${pkg.manifest.description} |`);
|
|
40505
|
-
}
|
|
40506
|
-
for (const pkg of byKind(input2, "agent")) {
|
|
40507
|
-
const name = names.get(pkg.manifest.name);
|
|
40508
|
-
const parts = agentParts(pkg, t.id, names, out);
|
|
40509
|
-
const skillBlocks = Object.keys(pkg.manifest.depends?.skills ?? {}).map((d) => byName.get(d)).filter((p) => !!p).map((p) => `## Skill: ${names.get(p.manifest.name)}
|
|
40510
|
-
|
|
40511
|
-
${splitFrontmatter(asText(p.files[skillEntryPath(p.manifest)]) ?? "").body.trim()}`);
|
|
40512
|
-
out.files.push({
|
|
40513
|
-
package: pkg.manifest.name,
|
|
40514
|
-
path: join(root, `agent-${name}.md`),
|
|
40515
|
-
content: `${header(pkg)}
|
|
40516
|
-
|
|
40517
|
-
# ${name}
|
|
40518
|
-
|
|
40519
|
-
${pkg.manifest.description}
|
|
40520
|
-
|
|
40521
|
-
${parts.prompt}${skillBlocks.length ? `
|
|
40522
|
-
|
|
40523
|
-
${skillBlocks.join("\n\n")}` : ""}
|
|
40524
|
-
`
|
|
40525
|
-
});
|
|
40526
|
-
rows.push(`| \`agent-${name}.md\` | agent | ${pkg.manifest.name}@${pkg.manifest.version} | ${pkg.manifest.description} |`);
|
|
40527
|
-
}
|
|
40528
|
-
const servers = toolsetServers(input2);
|
|
40529
|
-
if (servers.length) {
|
|
40530
|
-
out.notes.push(`${t.product} can't load MCP config from files. Connect these servers in ${t.product}'s settings: ${servers.map((s) => `${s.server.name} (${s.server.url ?? s.server.command})`).join(", ")}.`);
|
|
40531
|
-
}
|
|
40532
|
-
if (rows.length) {
|
|
40533
|
-
out.files.push({
|
|
40534
|
-
path: join(root, "README.md"),
|
|
40535
|
-
content: `<!-- managed by yarkr -->
|
|
40536
|
-
|
|
40537
|
-
# Yarkr instructions for ${t.product}
|
|
40538
|
-
|
|
40539
|
-
${t.product} doesn't read instruction files from disk, so \`yarkr sync\` writes them here for you to paste.
|
|
40540
|
-
|
|
40541
|
-
**Where to paste:** ${t.where}
|
|
40542
|
-
|
|
40543
|
-
${t.limits}
|
|
40544
|
-
|
|
40545
|
-
| File | Kind | Release | Use when |
|
|
40546
|
-
| --- | --- | --- | --- |
|
|
40547
|
-
${rows.join("\n")}
|
|
40548
|
-
|
|
40549
|
-
After \`yarkr update\`, re-paste any file whose release changed.
|
|
40550
|
-
`
|
|
40551
|
-
});
|
|
40552
|
-
out.notes.push(`${t.product} bundle written to ${root}/. Paste each file as described in ${root}/README.md.`);
|
|
40553
|
-
}
|
|
40554
|
-
},
|
|
40555
|
-
mcpSnippet: (mcpUrl) => ({
|
|
40556
|
-
file: t.mcpWhere,
|
|
40557
|
-
format: "text",
|
|
40558
|
-
content: `URL: ${mcpUrl}
|
|
40559
|
-
Header: Authorization: Bearer <your Yarkr API token>`,
|
|
40560
|
-
notes: [`${t.product} stores the token in its own connection settings. Use a token from a service account with read access only.`]
|
|
40561
|
-
})
|
|
40562
|
-
});
|
|
40563
|
-
}
|
|
40564
|
-
|
|
40565
|
-
// ../../packages/core/dist/harnesses/linear.js
|
|
40566
|
-
var linear = workspaceHarness({
|
|
40567
|
-
id: "linear",
|
|
40568
|
-
product: "Linear",
|
|
40569
|
-
where: "Workspace guidance: Settings \u2192 Agents \u2192 Additional guidance. Team guidance: Team settings \u2192 Agents \u2192 Additional guidance (team guidance takes priority). Paste the contents of the matching file.",
|
|
40570
|
-
limits: "Linear passes this guidance to every agent working on issues in the workspace or team, so keep each file focused.",
|
|
40571
|
-
mcpWhere: "Linear agents that support MCP: add a custom MCP server"
|
|
40572
|
-
});
|
|
40573
|
-
|
|
40574
|
-
// ../../packages/core/dist/harnesses/notion.js
|
|
40575
|
-
var notion = workspaceHarness({
|
|
40576
|
-
id: "notion",
|
|
40577
|
-
product: "Notion",
|
|
40578
|
-
where: "Create or open a Custom Agent \u2192 Instructions, and paste the contents of the matching file. For Notion AI personal instructions, use Settings \u2192 Notion AI \u2192 Instructions. MCP toolsets are added under the agent's Connections.",
|
|
40579
|
-
limits: "Notion instructions are plain text; reference files are inlined below the main instructions.",
|
|
40580
|
-
mcpWhere: "Notion Custom Agent \u2192 Connections \u2192 Add MCP server"
|
|
40581
|
-
});
|
|
40582
|
-
|
|
40583
|
-
// ../../packages/core/dist/harnesses/openai-agents-sdk.js
|
|
40584
|
-
var openaiAgentsSdk = defineHarness({
|
|
40585
|
-
id: "openai-agents-sdk",
|
|
40586
|
-
layout: {
|
|
40587
|
-
project: { root: "yarkr/agents-sdk" },
|
|
40588
|
-
user: { root: ".yarkr/agents-sdk" }
|
|
40589
|
-
},
|
|
40590
|
-
render({ input: input2, layout, names, out }) {
|
|
40591
|
-
const root = layout.root;
|
|
40592
|
-
for (const pkg of byKind(input2, "skill"))
|
|
40593
|
-
out.files.push(...skillFolderFiles(pkg, join(root, "skills"), names.get(pkg.manifest.name)));
|
|
40594
|
-
const servers = toolsetServers(input2).map(({ pkg, server: s }) => {
|
|
40595
|
-
const conv = (what) => (k, v) => convertSecretRefs(v, "keep", { pkg: pkg.manifest.name, server: s.name, key: `${what} ${k}` }, out.notes);
|
|
40596
|
-
return {
|
|
40597
|
-
toolset: pkg.manifest.name,
|
|
40598
|
-
def: clean({ name: s.name, transport: s.transport === "http" ? "streamable_http" : "stdio", command: s.command, args: s.args, url: s.url, env: mapValues(s.env, conv("env")), headers: mapValues(s.headers, conv("header")) })
|
|
40599
|
-
};
|
|
40600
|
-
});
|
|
40601
|
-
if (servers.length)
|
|
40602
|
-
out.files.push({ path: join(root, "mcp.json"), content: JSON.stringify({ managed_by: "yarkr", servers: servers.map((s) => s.def) }, null, 2) + "\n" });
|
|
40603
|
-
for (const pkg of byKind(input2, "agent")) {
|
|
40604
|
-
const name = names.get(pkg.manifest.name);
|
|
40605
|
-
const parts = agentParts(pkg, "openai-agents-sdk", names, out);
|
|
40606
|
-
const toolsetDeps = new Set(Object.keys(pkg.manifest.depends?.toolsets ?? {}));
|
|
40607
|
-
const def = clean({
|
|
40608
|
-
managed_by: "yarkr",
|
|
40609
|
-
package: pkg.manifest.name,
|
|
40610
|
-
version: pkg.manifest.version,
|
|
40611
|
-
name,
|
|
40612
|
-
handoff_description: pkg.manifest.description,
|
|
40613
|
-
instructions: parts.prompt,
|
|
40614
|
-
model: parts.model,
|
|
40615
|
-
model_settings: Object.keys(parts.parameters).length ? parts.parameters : void 0,
|
|
40616
|
-
tools: parts.tools,
|
|
40617
|
-
handoffs: parts.subagents,
|
|
40618
|
-
skills: parts.skills.map((s) => join("skills", s)),
|
|
40619
|
-
mcp_servers: servers.filter((s) => toolsetDeps.has(s.toolset)).map((s) => s.def.name),
|
|
40620
|
-
...parts.overrides
|
|
40621
|
-
});
|
|
40622
|
-
out.files.push({ package: pkg.manifest.name, path: join(root, "agents", `${name}.json`), content: JSON.stringify(def, null, 2) + "\n" });
|
|
40623
|
-
}
|
|
40624
|
-
},
|
|
40625
|
-
mcpSnippet: (mcpUrl, tokenEnv, notes) => ({
|
|
40626
|
-
file: "your agent code",
|
|
40627
|
-
format: "text",
|
|
40628
|
-
content: `MCPServerStreamableHttp(params={"url": "${mcpUrl}", "headers": {"Authorization": f"Bearer {os.environ['${tokenEnv}']}"}})`,
|
|
40629
|
-
notes
|
|
40630
|
-
})
|
|
40631
|
-
});
|
|
40632
|
-
|
|
40633
40340
|
// ../../packages/core/dist/harnesses/opencode.js
|
|
40634
40341
|
function opencodeModel(model) {
|
|
40635
40342
|
if (!model || model.includes("/"))
|
|
@@ -40673,14 +40380,9 @@ var opencode = nativeFolderHarness({
|
|
|
40673
40380
|
// ../../packages/core/dist/harnesses/index.js
|
|
40674
40381
|
var HARNESS_REGISTRY = {
|
|
40675
40382
|
"claude-code": claudeCode,
|
|
40676
|
-
"claude-cowork": claudeCowork,
|
|
40677
40383
|
codex,
|
|
40678
40384
|
opencode,
|
|
40679
40385
|
cursor,
|
|
40680
|
-
"openai-agents-sdk": openaiAgentsSdk,
|
|
40681
|
-
linear,
|
|
40682
|
-
notion,
|
|
40683
|
-
"custom-http": customHttp,
|
|
40684
40386
|
generic
|
|
40685
40387
|
};
|
|
40686
40388
|
function detectHarnesses(exists) {
|
|
@@ -40753,24 +40455,18 @@ function yarkrMcpSnippet(harness, mcpUrl, tokenEnv = "YARKR_TOKEN") {
|
|
|
40753
40455
|
notes
|
|
40754
40456
|
};
|
|
40755
40457
|
}
|
|
40756
|
-
var SCOPE = /^(all|public
|
|
40458
|
+
var SCOPE = /^(all|public|[a-z0-9][a-z0-9-]*(\/[a-z0-9][a-z0-9-]*)?)$/;
|
|
40757
40459
|
function isConnectionScope(scope) {
|
|
40758
40460
|
return SCOPE.test(scope);
|
|
40759
40461
|
}
|
|
40760
40462
|
function yarkrConnection(server, scope, tokenEnv = "YARKR_TOKEN") {
|
|
40761
40463
|
if (!isConnectionScope(scope))
|
|
40762
|
-
throw new Error(`"${scope}" isn't an MCP scope. Use all, public,
|
|
40464
|
+
throw new Error(`"${scope}" isn't an MCP scope. Use all, public, <org> or <org>/<ark>.`);
|
|
40763
40465
|
const base = server.replace(/\/+$/, "");
|
|
40764
40466
|
if (scope === "all")
|
|
40765
40467
|
return { scope, name: "yarkr", url: `${base}/mcp`, tokenEnv };
|
|
40766
40468
|
if (scope === "public")
|
|
40767
40469
|
return { scope, name: "yarkr-public", url: `${base}/mcp/public`, tokenEnv: null };
|
|
40768
|
-
if (scope === "@me")
|
|
40769
|
-
return { scope, name: "yarkr-me", url: `${base}/mcp/a/@me`, tokenEnv };
|
|
40770
|
-
if (scope.startsWith("@"))
|
|
40771
|
-
return { scope, name: `yarkr-${scope.slice(1).replace(/@\d+$/, "").replace("/", "-")}`, url: `${base}/mcp/${scope}`, tokenEnv };
|
|
40772
|
-
if (scope.startsWith("global/"))
|
|
40773
|
-
return { scope, name: `yarkr-${scope.replace("/", "-")}`, url: `${base}/mcp/a/${scope}`, tokenEnv };
|
|
40774
40470
|
return { scope, name: `yarkr-${scope.replace("/", "-")}`, url: `${base}/mcp/o/${scope}`, tokenEnv };
|
|
40775
40471
|
}
|
|
40776
40472
|
function connectionPackage(c) {
|
|
@@ -40832,7 +40528,48 @@ import { readFileSync } from "fs";
|
|
|
40832
40528
|
import { chmod, mkdir, readFile, writeFile } from "fs/promises";
|
|
40833
40529
|
import os from "os";
|
|
40834
40530
|
import path from "path";
|
|
40531
|
+
|
|
40532
|
+
// src/keychain.ts
|
|
40533
|
+
import { execFileSync, spawnSync } from "child_process";
|
|
40534
|
+
var SERVICE = "yarkr";
|
|
40535
|
+
var detected;
|
|
40536
|
+
function store() {
|
|
40537
|
+
if (process.env.YARKR_CREDENTIAL_STORE === "file") return null;
|
|
40538
|
+
if (detected !== void 0) return detected;
|
|
40539
|
+
const has = (cmd) => spawnSync("which", [cmd], { stdio: "ignore" }).status === 0;
|
|
40540
|
+
detected = process.platform === "darwin" && has("security") ? "macos" : process.platform === "linux" && has("secret-tool") ? "secret-service" : null;
|
|
40541
|
+
return detected;
|
|
40542
|
+
}
|
|
40543
|
+
function keychainName() {
|
|
40544
|
+
const s = store();
|
|
40545
|
+
return s === "macos" ? "the macOS Keychain" : s === "secret-service" ? "your keyring (Secret Service)" : null;
|
|
40546
|
+
}
|
|
40547
|
+
function keychainSet(account, token) {
|
|
40548
|
+
const s = store();
|
|
40549
|
+
if (!s || /["\n]/.test(account + token)) return false;
|
|
40550
|
+
const r = s === "macos" ? spawnSync("security", ["-i"], { input: `add-generic-password -U -s ${SERVICE} -a "${account}" -l "Yarkr (${account})" -w "${token}"
|
|
40551
|
+
`, stdio: ["pipe", "ignore", "ignore"] }) : spawnSync("secret-tool", ["store", `--label=Yarkr (${account})`, "service", SERVICE, "registry", account], { input: token, stdio: ["pipe", "ignore", "ignore"] });
|
|
40552
|
+
return r.status === 0 && keychainGet(account) === token;
|
|
40553
|
+
}
|
|
40554
|
+
function keychainGet(account) {
|
|
40555
|
+
const s = store();
|
|
40556
|
+
if (!s) return null;
|
|
40557
|
+
try {
|
|
40558
|
+
const out = s === "macos" ? execFileSync("security", ["find-generic-password", "-s", SERVICE, "-a", account, "-w"], { stdio: ["ignore", "pipe", "ignore"] }) : execFileSync("secret-tool", ["lookup", "service", SERVICE, "registry", account], { stdio: ["ignore", "pipe", "ignore"] });
|
|
40559
|
+
return out.toString("utf8").trim() || null;
|
|
40560
|
+
} catch {
|
|
40561
|
+
return null;
|
|
40562
|
+
}
|
|
40563
|
+
}
|
|
40564
|
+
function keychainDelete(account) {
|
|
40565
|
+
const s = store();
|
|
40566
|
+
if (s === "macos") spawnSync("security", ["delete-generic-password", "-s", SERVICE, "-a", account], { stdio: "ignore" });
|
|
40567
|
+
else if (s === "secret-service") spawnSync("secret-tool", ["clear", "service", SERVICE, "registry", account], { stdio: "ignore" });
|
|
40568
|
+
}
|
|
40569
|
+
|
|
40570
|
+
// src/rc.ts
|
|
40835
40571
|
var RC_FILE = ".yarkrrc";
|
|
40572
|
+
var KEYCHAIN_TOKEN = "@keychain";
|
|
40836
40573
|
var userRcPath = () => process.env.YARKR_USERCONFIG ?? path.join(os.homedir(), RC_FILE);
|
|
40837
40574
|
function parseRc(text, file2) {
|
|
40838
40575
|
const rc = { path: file2, tokens: /* @__PURE__ */ new Map() };
|
|
@@ -40869,6 +40606,11 @@ function tokenFor(rc, server) {
|
|
|
40869
40606
|
for (const k of rc.tokens.keys()) if (key.startsWith(k) && (!best || k.length > best.length)) best = k;
|
|
40870
40607
|
if (!best) return void 0;
|
|
40871
40608
|
const raw = rc.tokens.get(best);
|
|
40609
|
+
if (raw === KEYCHAIN_TOKEN) {
|
|
40610
|
+
const token = keychainGet(best);
|
|
40611
|
+
if (!token) throw new CliError(`${rc.path} says the token for ${best} is in your keychain, but it isn't there.`, "Run `yarkr login` again.");
|
|
40612
|
+
return token;
|
|
40613
|
+
}
|
|
40872
40614
|
const value = raw.replace(/\$\{([A-Za-z_][A-Za-z0-9_]*)(\?)?\}/g, (_, name, optional2) => {
|
|
40873
40615
|
const v = process.env[name];
|
|
40874
40616
|
if (v === void 0 && !optional2) {
|
|
@@ -40880,7 +40622,7 @@ function tokenFor(rc, server) {
|
|
|
40880
40622
|
}
|
|
40881
40623
|
function warnOnLiteralTokens(rc) {
|
|
40882
40624
|
for (const [k, v] of rc.tokens) {
|
|
40883
|
-
if (!v.includes("${")) ui.warn(`${rc.path} has a literal token for ${k}. Use \${ENV_VAR} instead if you commit this file.`);
|
|
40625
|
+
if (!v.includes("${") && v !== KEYCHAIN_TOKEN) ui.warn(`${rc.path} has a literal token for ${k}. Use \${ENV_VAR} instead if you commit this file.`);
|
|
40884
40626
|
}
|
|
40885
40627
|
}
|
|
40886
40628
|
var authTokenKey = (server) => `${registryKey(server)}:_authToken`;
|
|
@@ -40911,7 +40653,7 @@ async function setRcValue(file2, key, value, { secret = false } = {}) {
|
|
|
40911
40653
|
var CONFIG_FILE = "yarkr.json";
|
|
40912
40654
|
var LOCK_FILE = "yarkr.lock";
|
|
40913
40655
|
var normalizeServer = (url2) => url2.replace(/\/+$/, "");
|
|
40914
|
-
var DEFAULT_REGISTRY = "https://yarkr.com";
|
|
40656
|
+
var DEFAULT_REGISTRY = "https://api.yarkr.com/functions/v1/api";
|
|
40915
40657
|
var connectionFor = (server, m) => yarkrConnection(server, m.scope, m.public ? null : m.token_env);
|
|
40916
40658
|
var userStateDir = () => process.env.YARKR_STATE_DIR ?? path2.join(process.env.XDG_CONFIG_HOME ?? path2.join(os2.homedir(), ".config"), "yarkr");
|
|
40917
40659
|
async function loadProjectConfig(dir, { required: required2 = true } = {}) {
|
|
@@ -40933,10 +40675,7 @@ async function loadProjectConfig(dir, { required: required2 = true } = {}) {
|
|
|
40933
40675
|
const unknown2 = harnesses.filter((h) => !HARNESS_IDS.includes(h));
|
|
40934
40676
|
if (unknown2.length) throw new CliError(`${CONFIG_FILE} lists unknown harnesses: ${unknown2.join(", ")}.`, `Known harnesses: ${HARNESS_IDS.join(", ")}.`);
|
|
40935
40677
|
if (raw.arks !== void 0 && raw.arks !== "auto" && !(Array.isArray(raw.arks) && raw.arks.every((a) => typeof a === "string"))) {
|
|
40936
|
-
throw new CliError(`${CONFIG_FILE}: "arks" must be "auto" or a list of ark refs.`, `For example "arks": ["acme/finance", "
|
|
40937
|
-
}
|
|
40938
|
-
if (raw.collections !== void 0 && !(Array.isArray(raw.collections) && raw.collections.every((c) => typeof c === "string" && parseCollectionRef(c)))) {
|
|
40939
|
-
throw new CliError(`${CONFIG_FILE}: "collections" must be a list of collection refs.`, `For example "collections": ["@ana/pdf", "@acme-bot/review@3"].`);
|
|
40678
|
+
throw new CliError(`${CONFIG_FILE}: "arks" must be "auto" or a list of ark refs.`, `For example "arks": ["acme/finance", "@me"].`);
|
|
40940
40679
|
}
|
|
40941
40680
|
const mcp = (raw.mcp ?? []).map((m) => typeof m === "string" ? { scope: m } : m);
|
|
40942
40681
|
for (const m of mcp) {
|
|
@@ -40952,7 +40691,6 @@ async function loadProjectConfig(dir, { required: required2 = true } = {}) {
|
|
|
40952
40691
|
layout: raw.layout,
|
|
40953
40692
|
...raw.arks !== void 0 ? { arks: raw.arks } : {},
|
|
40954
40693
|
...raw.exclude?.length ? { exclude: raw.exclude } : {},
|
|
40955
|
-
...raw.collections?.length ? { collections: raw.collections } : {},
|
|
40956
40694
|
...mcp.length ? { mcp } : {}
|
|
40957
40695
|
};
|
|
40958
40696
|
}
|
|
@@ -40965,7 +40703,6 @@ async function saveProjectConfig(dir, cfg) {
|
|
|
40965
40703
|
};
|
|
40966
40704
|
if (cfg.arks !== void 0) out.arks = cfg.arks;
|
|
40967
40705
|
if (cfg.exclude?.length) out.exclude = [...cfg.exclude].sort();
|
|
40968
|
-
if (cfg.collections?.length) out.collections = [...cfg.collections].sort();
|
|
40969
40706
|
if (cfg.mcp?.length) out.mcp = cfg.mcp.map((m) => m.token_env || m.public ? m : m.scope);
|
|
40970
40707
|
if (cfg.layout && Object.keys(cfg.layout).length) out.layout = cfg.layout;
|
|
40971
40708
|
await writeFile2(path2.join(dir, CONFIG_FILE), JSON.stringify(out, null, 2) + "\n");
|
|
@@ -41020,12 +40757,13 @@ async function resolveConnection(opts) {
|
|
|
41020
40757
|
}
|
|
41021
40758
|
|
|
41022
40759
|
// src/commands/auth.ts
|
|
40760
|
+
async function readStdin() {
|
|
40761
|
+
const chunks = [];
|
|
40762
|
+
for await (const c of process.stdin) chunks.push(c);
|
|
40763
|
+
return Buffer.concat(chunks).toString("utf8").trim();
|
|
40764
|
+
}
|
|
41023
40765
|
async function promptHidden(question) {
|
|
41024
|
-
if (!process.stdin.isTTY)
|
|
41025
|
-
const chunks = [];
|
|
41026
|
-
for await (const c of process.stdin) chunks.push(c);
|
|
41027
|
-
return Buffer.concat(chunks).toString("utf8").trim();
|
|
41028
|
-
}
|
|
40766
|
+
if (!process.stdin.isTTY) return readStdin();
|
|
41029
40767
|
let muted = false;
|
|
41030
40768
|
const output3 = new Writable({
|
|
41031
40769
|
write(chunk, _enc, cb) {
|
|
@@ -41041,30 +40779,99 @@ async function promptHidden(question) {
|
|
|
41041
40779
|
process.stdout.write("\n");
|
|
41042
40780
|
return answer.trim();
|
|
41043
40781
|
}
|
|
40782
|
+
function registryFor(flag, userRc) {
|
|
40783
|
+
return normalizeServer(flag ?? process.env.YARKR_REGISTRY ?? loadRc(path3.join(process.cwd(), RC_FILE))?.registry ?? userRc?.registry ?? DEFAULT_REGISTRY);
|
|
40784
|
+
}
|
|
41044
40785
|
async function login(opts) {
|
|
41045
40786
|
const userRc = loadRc(userRcPath());
|
|
41046
|
-
const registry2 =
|
|
40787
|
+
const registry2 = registryFor(opts.registry, userRc);
|
|
41047
40788
|
let token = opts.token ?? process.env.YARKR_TOKEN;
|
|
41048
|
-
if (!token)
|
|
41049
|
-
|
|
41050
|
-
token = await promptHidden("Paste the token: ");
|
|
41051
|
-
}
|
|
40789
|
+
if (!token && !process.stdin.isTTY) token = await readStdin();
|
|
40790
|
+
if (!token) token = await browserLogin(registry2, opts.browser !== false && !headless());
|
|
41052
40791
|
if (!token) throw new CliError("No token entered.");
|
|
41053
40792
|
const me = await new Api({ server: registry2, token }).me();
|
|
41054
|
-
|
|
40793
|
+
const store2 = keychainSet(registryKey(registry2), token) ? keychainName() : null;
|
|
40794
|
+
await setRcValue(userRcPath(), authTokenKey(registry2), store2 ? KEYCHAIN_TOKEN : token, { secret: true });
|
|
41055
40795
|
if (!userRc?.registry) await setRcValue(userRcPath(), "registry", registry2, { secret: true });
|
|
41056
40796
|
ui.ok(`Signed in to ${registry2} as ${ui.bold(me.email)}.`);
|
|
41057
|
-
ui.step(`Token saved to ${userRcPath()} (readable only by you).`);
|
|
40797
|
+
ui.step(store2 ? `Token saved to ${store2}.` : `Token saved to ${userRcPath()} (readable only by you).`);
|
|
40798
|
+
}
|
|
40799
|
+
var LOGIN_TIMEOUT_MS = 5 * 6e4;
|
|
40800
|
+
var headless = () => !!process.env.SSH_CONNECTION || process.platform === "linux" && !process.env.DISPLAY && !process.env.WAYLAND_DISPLAY;
|
|
40801
|
+
async function browserLogin(registry2, open2, openUrl = openBrowser) {
|
|
40802
|
+
const info2 = await new Api({ server: registry2, token: null }).info();
|
|
40803
|
+
const web = (info2.web_url ?? registry2).replace(/\/+$/, "");
|
|
40804
|
+
const host = os3.hostname().replace(/\.local$/, "");
|
|
40805
|
+
if (!open2) {
|
|
40806
|
+
ui.info("Open this link on any device, sign in and approve:");
|
|
40807
|
+
console.log(`
|
|
40808
|
+
${ui.code(`${web}/cli/login?${new URLSearchParams({ host })}`)}
|
|
40809
|
+
`);
|
|
40810
|
+
return promptHidden("Paste the token it shows: ");
|
|
40811
|
+
}
|
|
40812
|
+
const state = randomBytes(16).toString("base64url");
|
|
40813
|
+
return new Promise((resolve, reject) => {
|
|
40814
|
+
const done = (err, token) => {
|
|
40815
|
+
clearTimeout(timer);
|
|
40816
|
+
server.close();
|
|
40817
|
+
if (err) reject(err);
|
|
40818
|
+
else resolve(token);
|
|
40819
|
+
};
|
|
40820
|
+
const server = createServer((req, res) => {
|
|
40821
|
+
if (req.method !== "POST" || req.url !== "/callback") return void res.writeHead(404).end();
|
|
40822
|
+
let body = "";
|
|
40823
|
+
req.setEncoding("utf8");
|
|
40824
|
+
req.on("data", (c) => {
|
|
40825
|
+
body += c;
|
|
40826
|
+
if (body.length > 8192) req.destroy();
|
|
40827
|
+
});
|
|
40828
|
+
req.on("end", () => {
|
|
40829
|
+
const form = new URLSearchParams(body);
|
|
40830
|
+
if (form.get("state") !== state) return void res.writeHead(400, { "content-type": "text/plain" }).end("This sign-in link is stale. Run `yarkr login` again.");
|
|
40831
|
+
const token = form.get("token");
|
|
40832
|
+
res.writeHead(303, { location: `${web}/cli/login?${new URLSearchParams({ done: token ? "ok" : "denied" })}`, connection: "close" });
|
|
40833
|
+
res.end(() => done(token ? null : new CliError("Sign-in was cancelled in the browser."), token ?? void 0));
|
|
40834
|
+
});
|
|
40835
|
+
});
|
|
40836
|
+
const timer = setTimeout(() => done(new CliError("Timed out waiting for the browser.", "Run `yarkr login` again, or `yarkr login --no-browser` to paste a token.")), LOGIN_TIMEOUT_MS);
|
|
40837
|
+
server.on("error", (err) => done(err));
|
|
40838
|
+
server.listen(0, "127.0.0.1", () => {
|
|
40839
|
+
const { port } = server.address();
|
|
40840
|
+
const url2 = `${web}/cli/login?${new URLSearchParams({ port: String(port), state, host })}`;
|
|
40841
|
+
ui.info(`Opening your browser to sign in to ${ui.bold(web)}\u2026`);
|
|
40842
|
+
ui.step(`If it doesn't open, visit ${ui.code(url2)}`);
|
|
40843
|
+
openUrl(url2);
|
|
40844
|
+
});
|
|
40845
|
+
});
|
|
40846
|
+
}
|
|
40847
|
+
function openBrowser(url2) {
|
|
40848
|
+
const [cmd, args] = process.platform === "darwin" ? ["open", [url2]] : process.platform === "win32" ? ["rundll32", ["url.dll,FileProtocolHandler", url2]] : ["xdg-open", [url2]];
|
|
40849
|
+
try {
|
|
40850
|
+
const child = spawn(cmd, args, { stdio: "ignore", detached: true });
|
|
40851
|
+
child.on("error", () => {
|
|
40852
|
+
});
|
|
40853
|
+
child.unref();
|
|
40854
|
+
} catch {
|
|
40855
|
+
}
|
|
41058
40856
|
}
|
|
41059
40857
|
async function logout(opts) {
|
|
41060
40858
|
const userRc = loadRc(userRcPath());
|
|
41061
|
-
const registry2 =
|
|
41062
|
-
|
|
40859
|
+
const registry2 = registryFor(opts.registry, userRc);
|
|
40860
|
+
let token;
|
|
40861
|
+
try {
|
|
40862
|
+
token = userRc ? tokenFor(userRc, registry2) : void 0;
|
|
40863
|
+
} catch {
|
|
40864
|
+
token = null;
|
|
40865
|
+
}
|
|
40866
|
+
if (token === void 0) {
|
|
41063
40867
|
ui.info("You aren't signed in.");
|
|
41064
40868
|
return;
|
|
41065
40869
|
}
|
|
40870
|
+
const revoked = token ? await new Api({ server: registry2, token }).revokeCurrentToken().then(() => true, () => false) : false;
|
|
40871
|
+
keychainDelete(registryKey(registry2));
|
|
41066
40872
|
await setRcValue(userRcPath(), authTokenKey(registry2), null, { secret: true });
|
|
41067
|
-
ui.ok(`Signed out of ${registry2}
|
|
40873
|
+
ui.ok(`Signed out of ${registry2}.`);
|
|
40874
|
+
if (!revoked) ui.step("The token may still exist on the server; revoke it in Settings \u2192 API tokens if you no longer need it.");
|
|
41068
40875
|
}
|
|
41069
40876
|
async function whoami(opts) {
|
|
41070
40877
|
const conn = await resolveConnection({ registry: opts.registry, dir: process.cwd() });
|
|
@@ -41072,28 +40879,28 @@ async function whoami(opts) {
|
|
|
41072
40879
|
ui.ok(`${ui.bold(me.name)} <${me.email}> on ${conn.server}`);
|
|
41073
40880
|
if (conn.tokenSource) ui.step(`token from ${conn.tokenSource}`);
|
|
41074
40881
|
if (me.is_admin) ui.step("admin");
|
|
41075
|
-
if (me.
|
|
40882
|
+
if (me.orgs.length) ui.step(`orgs: ${me.orgs.map((o) => `${o.slug}${o.role === "admin" ? " (admin)" : ""}`).join(", ")}`);
|
|
41076
40883
|
}
|
|
41077
40884
|
|
|
41078
40885
|
// src/commands/registry.ts
|
|
41079
40886
|
var pct = (v) => v === null ? ui.dim("\u2014") : `${Math.round(v * 100)}%`;
|
|
41080
40887
|
async function search(query, opts) {
|
|
41081
|
-
const
|
|
41082
|
-
const page = await
|
|
40888
|
+
const api = new Api(await resolveConnection({ dir: process.cwd() }));
|
|
40889
|
+
const page = await api.search({ q: query, kind: opts.kind, target: opts.target });
|
|
41083
40890
|
if (opts.json) return console.log(JSON.stringify(page, null, 2));
|
|
41084
40891
|
if (!page.items.length) {
|
|
41085
|
-
ui.info(query ? `Nothing matches "${query}".` : "Nothing here yet.
|
|
40892
|
+
ui.info(query ? `Nothing matches "${query}".` : "Nothing here yet. Publish by installing the Yarkr GitHub App on your repos (Settings \u2192 GitHub).");
|
|
41086
40893
|
return;
|
|
41087
40894
|
}
|
|
41088
40895
|
ui.table(
|
|
41089
|
-
page.items.map((p) => [ui.bold(p.name), p.kind, p.channels.find((c) => c.name === "stable")?.version ?? ui.dim("unreleased"), pct(p.
|
|
40896
|
+
page.items.map((p) => [ui.bold(p.name), p.kind, p.channels.find((c) => c.name === "stable")?.version ?? ui.dim("unreleased"), pct(p.reported_eval?.pass_rate ?? null), p.description.slice(0, 60)]),
|
|
41090
40897
|
["package", "kind", "stable", "evals", "description"]
|
|
41091
40898
|
);
|
|
41092
40899
|
if (page.total > page.items.length) ui.step(`${page.total - page.items.length} more \u2014 narrow the search.`);
|
|
41093
40900
|
}
|
|
41094
40901
|
async function info(name, opts) {
|
|
41095
|
-
const
|
|
41096
|
-
const p = await
|
|
40902
|
+
const api = new Api(await resolveConnection({ dir: process.cwd() }));
|
|
40903
|
+
const p = await api.pkg(name);
|
|
41097
40904
|
if (opts.json) return console.log(JSON.stringify(p, null, 2));
|
|
41098
40905
|
ui.heading(`${p.name} ${ui.dim(p.kind)}`);
|
|
41099
40906
|
console.log(` ${p.description}`);
|
|
@@ -41106,20 +40913,28 @@ async function info(name, opts) {
|
|
|
41106
40913
|
["tags", p.tags.join(", ") || ui.dim("\u2014")],
|
|
41107
40914
|
["classification", p.classification],
|
|
41108
40915
|
["source", p.source ? `${p.source.repo}/${p.source.path}` : ui.dim("\u2014")],
|
|
41109
|
-
["
|
|
41110
|
-
["reported evals", p.reported_eval ? `${pct(p.reported_eval.pass_rate)} ${ui.dim(p.reported_eval.trust)}` : ui.dim("\u2014")]
|
|
40916
|
+
["evals", p.reported_eval ? `${pct(p.reported_eval.pass_rate)} ${ui.dim(p.reported_eval.trust)}` : ui.dim("\u2014")]
|
|
41111
40917
|
].map(([k, v]) => [ui.dim(k), v])
|
|
41112
40918
|
);
|
|
41113
40919
|
if (p.releases.length) {
|
|
41114
40920
|
console.log();
|
|
41115
40921
|
ui.table(
|
|
41116
|
-
p.releases.slice(0, 10).map((r) => [r.version, r.channels.join(", "), pct(r.eval_score), r.commit_sha?.slice(0, 7) ?? "", r.created_at.slice(0, 10)]),
|
|
40922
|
+
p.releases.slice(0, 10).map((r) => [r.version, r.yanked ? ui.del(`yanked: ${r.yanked.reason}`) : r.channels.join(", "), pct(r.eval_score), r.commit_sha?.slice(0, 7) ?? "", r.created_at.slice(0, 10)]),
|
|
41117
40923
|
["release", "channels", "evals", "commit", "date"]
|
|
41118
40924
|
);
|
|
41119
40925
|
}
|
|
41120
40926
|
console.log();
|
|
41121
40927
|
ui.step(`Install: ${ui.code(`yarkr add ${p.name}`)}`);
|
|
41122
40928
|
}
|
|
40929
|
+
async function yank(spec, opts) {
|
|
40930
|
+
const at = spec.lastIndexOf("@");
|
|
40931
|
+
if (at < 1) throw new CliError(`Name the release: <namespace/name>@<version>, e.g. acme/pdf@1.4.0.`);
|
|
40932
|
+
const [name, version2] = [spec.slice(0, at), spec.slice(at + 1)];
|
|
40933
|
+
if (!opts.undo && !opts.reason) throw new CliError("Say why with --reason: people who installed it see it.", `yarkr yank ${spec} --reason "leaks a token"`);
|
|
40934
|
+
const api = new Api(await resolveConnection({ dir: process.cwd() }));
|
|
40935
|
+
await api.yank(name, version2, opts.undo ? null : opts.reason);
|
|
40936
|
+
ui.ok(opts.undo ? `${name}@${version2} is no longer yanked.` : `Yanked ${name}@${version2}. Ranges and stable skip it now; lockfiles that pin it still install it, with a warning.`);
|
|
40937
|
+
}
|
|
41123
40938
|
async function mcpConfig(harness, opts) {
|
|
41124
40939
|
if (!HARNESS_IDS.includes(harness)) throw new CliError(`Unknown harness "${harness}".`, `Choose one of: ${HARNESS_IDS.join(", ")}.`);
|
|
41125
40940
|
const conn = await resolveConnection({ registry: opts.registry, dir: process.cwd() });
|
|
@@ -41140,13 +40955,13 @@ async function mcpConfig(harness, opts) {
|
|
|
41140
40955
|
// src/commands/project.ts
|
|
41141
40956
|
import { existsSync as existsSync3 } from "fs";
|
|
41142
40957
|
import { mkdir as mkdir3 } from "fs/promises";
|
|
41143
|
-
import
|
|
40958
|
+
import os5 from "os";
|
|
41144
40959
|
import path5 from "path";
|
|
41145
40960
|
|
|
41146
40961
|
// src/sync.ts
|
|
41147
40962
|
import { mkdir as mkdir2, readFile as readFile3, rm, writeFile as writeFile3, readdir, rmdir } from "fs/promises";
|
|
41148
40963
|
import { existsSync as existsSync2 } from "fs";
|
|
41149
|
-
import
|
|
40964
|
+
import os4 from "os";
|
|
41150
40965
|
import path4 from "path";
|
|
41151
40966
|
|
|
41152
40967
|
// ../../packages/core/dist/hash.js
|
|
@@ -41311,17 +41126,41 @@ var dirname = (p) => p.includes("/") ? p.slice(0, p.lastIndexOf("/")) : "";
|
|
|
41311
41126
|
var basename = (p) => p.slice(p.lastIndexOf("/") + 1);
|
|
41312
41127
|
var under = (dir, p) => dir ? p.startsWith(`${dir}/`) : true;
|
|
41313
41128
|
var rel = (dir, p) => dir ? p.slice(dir.length + 1) : p;
|
|
41314
|
-
function parseOverrides(text,
|
|
41129
|
+
function parseOverrides(text, path18, problems) {
|
|
41315
41130
|
if (text === null)
|
|
41316
41131
|
return null;
|
|
41317
41132
|
try {
|
|
41318
41133
|
const raw = import_yaml3.default.parse(text);
|
|
41319
41134
|
return raw && typeof raw === "object" ? raw : null;
|
|
41320
41135
|
} catch (err) {
|
|
41321
|
-
problems.push({ path:
|
|
41136
|
+
problems.push({ path: path18, message: `${MANIFEST_FILE} isn't valid YAML: ${err.message}` });
|
|
41322
41137
|
return null;
|
|
41323
41138
|
}
|
|
41324
41139
|
}
|
|
41140
|
+
function parseIndex(text, path18, problems) {
|
|
41141
|
+
let raw;
|
|
41142
|
+
try {
|
|
41143
|
+
raw = import_yaml3.default.parse(text ?? "");
|
|
41144
|
+
} catch (err) {
|
|
41145
|
+
problems.push({ path: path18, message: `isn't valid YAML: ${err.message}` });
|
|
41146
|
+
return null;
|
|
41147
|
+
}
|
|
41148
|
+
const entries = (key) => {
|
|
41149
|
+
const list = raw?.[key] ?? [];
|
|
41150
|
+
if (!Array.isArray(list)) {
|
|
41151
|
+
problems.push({ path: path18, message: `\`${key}\` must be a list.` });
|
|
41152
|
+
return [];
|
|
41153
|
+
}
|
|
41154
|
+
return list.flatMap((e, i) => {
|
|
41155
|
+
const entry = typeof e === "string" ? { path: e } : e;
|
|
41156
|
+
if (entry && typeof entry === "object" && typeof entry.path === "string" && entry.path.trim())
|
|
41157
|
+
return [{ ...entry, path: entry.path.replace(/^\.?\/+|\/+$/g, "") }];
|
|
41158
|
+
problems.push({ path: path18, message: `${key}[${i}] needs a \`path\`.` });
|
|
41159
|
+
return [];
|
|
41160
|
+
});
|
|
41161
|
+
};
|
|
41162
|
+
return { skills: entries("skills"), agents: entries("agents"), toolsets: entries("toolsets"), detect: raw?.detect !== false };
|
|
41163
|
+
}
|
|
41325
41164
|
var asList = (v) => Array.isArray(v) ? v.map(String) : typeof v === "string" ? v.split(",").map((s) => s.trim()).filter(Boolean) : [];
|
|
41326
41165
|
async function detectAssets(input2) {
|
|
41327
41166
|
const root = (input2.root ?? "").replace(/^\/+|\/+$/g, "");
|
|
@@ -41332,7 +41171,7 @@ async function detectAssets(input2) {
|
|
|
41332
41171
|
const claimed = [];
|
|
41333
41172
|
const isClaimed = (p) => claimed.some((d) => d ? p === d || p.startsWith(`${d}/`) : true);
|
|
41334
41173
|
const filesBelow = (dir) => new Map(paths.filter((p) => under(dir, p)).map((p) => [rel(dir, p), p]));
|
|
41335
|
-
const make = (name, kind,
|
|
41174
|
+
const make = (name, kind, path18, files, o, extra) => {
|
|
41336
41175
|
const suites = [...files.keys()].filter((p) => SUITE.test(p));
|
|
41337
41176
|
const raw = {
|
|
41338
41177
|
name: `${input2.namespace}/${slugify2(name)}`,
|
|
@@ -41351,19 +41190,109 @@ async function detectAssets(input2) {
|
|
|
41351
41190
|
};
|
|
41352
41191
|
const res = Manifest.safeParse(raw);
|
|
41353
41192
|
if (!res.success) {
|
|
41354
|
-
problems.push({ path:
|
|
41193
|
+
problems.push({ path: path18, message: res.error.issues.map((i) => `${i.path.join(".") || "manifest"}: ${i.message}`).join("; ") });
|
|
41355
41194
|
return null;
|
|
41356
41195
|
}
|
|
41357
|
-
return { name: slugify2(name), kind, path:
|
|
41196
|
+
return { name: slugify2(name), kind, path: path18, manifest: res.data, files };
|
|
41358
41197
|
};
|
|
41359
41198
|
const manifestNear = async (dir, from) => {
|
|
41360
41199
|
const mp = dir ? `${dir}/${MANIFEST_FILE}` : MANIFEST_FILE;
|
|
41361
41200
|
return paths.includes(mp) ? parseOverrides(await input2.read(mp), from, problems) ?? {} : {};
|
|
41362
41201
|
};
|
|
41202
|
+
const readFrontmatter = async (p) => {
|
|
41203
|
+
try {
|
|
41204
|
+
return splitFrontmatter(await input2.read(p) ?? "").data;
|
|
41205
|
+
} catch (err) {
|
|
41206
|
+
problems.push({ path: p, message: `frontmatter isn't valid YAML: ${err.message}` });
|
|
41207
|
+
return null;
|
|
41208
|
+
}
|
|
41209
|
+
};
|
|
41210
|
+
const agentAsset = (p, fm, e = {}) => {
|
|
41211
|
+
const name = e.name ?? (typeof fm.name === "string" && fm.name.trim() ? fm.name : basename(p).replace(/\.md$/, ""));
|
|
41212
|
+
const skills = asList(e.skills ?? fm.skills);
|
|
41213
|
+
const depends = skills.length ? { skills: Object.fromEntries(skills.map((s) => [s.includes("/") ? s : `${input2.namespace}/${slugify2(s)}`, "*"])) } : {};
|
|
41214
|
+
const model = e.model ?? fm.model;
|
|
41215
|
+
return make(name, "agent", p, /* @__PURE__ */ new Map([["AGENT.md", p]]), { targets: e.targets, tags: e.tags, evals: e.evals }, {
|
|
41216
|
+
description: e.description ?? String(fm.description),
|
|
41217
|
+
depends,
|
|
41218
|
+
agent: { system_prompt: "AGENT.md", model: typeof model === "string" ? model : void 0, tools: asList(e.tools ?? fm.tools), subagents: [] }
|
|
41219
|
+
});
|
|
41220
|
+
};
|
|
41221
|
+
const indexPath = root ? `${root}/${INDEX_FILE}` : INDEX_FILE;
|
|
41222
|
+
const index2 = paths.includes(indexPath) ? parseIndex(await input2.read(indexPath), indexPath, problems) : null;
|
|
41223
|
+
const listed = /* @__PURE__ */ new Set();
|
|
41224
|
+
const at = (e) => root ? `${root}/${e.path}` : e.path;
|
|
41225
|
+
const missing = (p, what) => problems.push({ path: indexPath, message: `${p} isn't in the repo (listed under ${what}).` });
|
|
41226
|
+
for (const e of index2?.skills ?? []) {
|
|
41227
|
+
const p = at(e);
|
|
41228
|
+
const isFile = paths.includes(p);
|
|
41229
|
+
if (!isFile && !paths.some((x) => x.startsWith(`${p}/`))) {
|
|
41230
|
+
missing(p, "skills");
|
|
41231
|
+
continue;
|
|
41232
|
+
}
|
|
41233
|
+
const entry = isFile ? basename(p) : e.entry ?? (paths.includes(`${p}/SKILL.md`) ? "SKILL.md" : "README.md");
|
|
41234
|
+
const entryPath = isFile ? p : `${p}/${entry}`;
|
|
41235
|
+
if (!paths.includes(entryPath)) {
|
|
41236
|
+
problems.push({ path: indexPath, message: `${p} has no ${entry}. Set \`entry\` to the file with the skill's instructions.` });
|
|
41237
|
+
continue;
|
|
41238
|
+
}
|
|
41239
|
+
const fm = await readFrontmatter(entryPath);
|
|
41240
|
+
if (!fm)
|
|
41241
|
+
continue;
|
|
41242
|
+
const description = e.description ?? (typeof fm.description === "string" ? fm.description : "");
|
|
41243
|
+
if (!description) {
|
|
41244
|
+
problems.push({ path: indexPath, message: `${p} needs a \`description\` (here or in its frontmatter): harnesses use it to decide when to load the skill.` });
|
|
41245
|
+
continue;
|
|
41246
|
+
}
|
|
41247
|
+
listed.add(entryPath);
|
|
41248
|
+
if (!isFile)
|
|
41249
|
+
claimed.push(p);
|
|
41250
|
+
const name = e.name ?? (typeof fm.name === "string" && fm.name.trim() ? fm.name : basename(p).replace(/\.mdc?$/, ""));
|
|
41251
|
+
const near = isFile ? {} : await manifestNear(p, entryPath);
|
|
41252
|
+
const o = { ...near, ...e.targets && { targets: e.targets }, ...e.tags && { tags: e.tags }, ...e.evals && { evals: e.evals }, ...entry !== "SKILL.md" && { entry } };
|
|
41253
|
+
const asset = make(name, "skill", p, isFile ? /* @__PURE__ */ new Map([[entry, p]]) : filesBelow(p), o, { description });
|
|
41254
|
+
if (asset)
|
|
41255
|
+
found.push(asset);
|
|
41256
|
+
}
|
|
41257
|
+
for (const e of index2?.agents ?? []) {
|
|
41258
|
+
const p = at(e);
|
|
41259
|
+
if (!paths.includes(p)) {
|
|
41260
|
+
missing(p, "agents");
|
|
41261
|
+
continue;
|
|
41262
|
+
}
|
|
41263
|
+
const fm = await readFrontmatter(p);
|
|
41264
|
+
if (!fm)
|
|
41265
|
+
continue;
|
|
41266
|
+
if (!e.description && typeof fm.description !== "string") {
|
|
41267
|
+
problems.push({ path: indexPath, message: `${p} needs a \`description\` (here or in its frontmatter): it says when to hand work to the agent.` });
|
|
41268
|
+
continue;
|
|
41269
|
+
}
|
|
41270
|
+
listed.add(p);
|
|
41271
|
+
const asset = agentAsset(p, fm, e);
|
|
41272
|
+
if (asset)
|
|
41273
|
+
found.push(asset);
|
|
41274
|
+
}
|
|
41275
|
+
for (const e of index2?.toolsets ?? []) {
|
|
41276
|
+
const p = at(e);
|
|
41277
|
+
if (!paths.includes(p)) {
|
|
41278
|
+
missing(p, "toolsets");
|
|
41279
|
+
continue;
|
|
41280
|
+
}
|
|
41281
|
+
listed.add(p);
|
|
41282
|
+
const servers = toolsetServers2(await input2.read(p), p, problems);
|
|
41283
|
+
if (!servers)
|
|
41284
|
+
continue;
|
|
41285
|
+
const description = e.description ?? `MCP servers: ${servers.map((s) => s.name).join(", ")}`;
|
|
41286
|
+
const o = { targets: e.targets, tags: e.tags, evals: e.evals };
|
|
41287
|
+
const asset = make(e.name ?? input2.repoName, "toolset", p, /* @__PURE__ */ new Map([[".mcp.json", p]]), o, { description, toolset: { servers, tool_schemas: [] } });
|
|
41288
|
+
if (asset)
|
|
41289
|
+
found.push(asset);
|
|
41290
|
+
}
|
|
41291
|
+
const detect = index2?.detect ?? true;
|
|
41363
41292
|
const depth = (p) => p.split("/").length;
|
|
41364
|
-
for (const p of paths.filter((x) => basename(x) === "SKILL.md").sort((a, b) => depth(a) - depth(b) || a.localeCompare(b))) {
|
|
41293
|
+
for (const p of paths.filter((x) => detect && basename(x) === "SKILL.md").sort((a, b) => depth(a) - depth(b) || a.localeCompare(b))) {
|
|
41365
41294
|
const dir = dirname(p);
|
|
41366
|
-
if (isClaimed(dir))
|
|
41295
|
+
if (isClaimed(dir) || listed.has(p))
|
|
41367
41296
|
continue;
|
|
41368
41297
|
let fm;
|
|
41369
41298
|
try {
|
|
@@ -41383,7 +41312,7 @@ async function detectAssets(input2) {
|
|
|
41383
41312
|
if (asset)
|
|
41384
41313
|
found.push(asset);
|
|
41385
41314
|
}
|
|
41386
|
-
for (const p of paths.filter((x) => basename(x) === MANIFEST_FILE)) {
|
|
41315
|
+
for (const p of paths.filter((x) => detect && basename(x) === MANIFEST_FILE)) {
|
|
41387
41316
|
const dir = dirname(p);
|
|
41388
41317
|
if (isClaimed(dir))
|
|
41389
41318
|
continue;
|
|
@@ -41396,34 +41325,15 @@ async function detectAssets(input2) {
|
|
|
41396
41325
|
if (asset)
|
|
41397
41326
|
found.push(asset);
|
|
41398
41327
|
}
|
|
41399
|
-
for (const p of paths.filter((x) => AGENT_FILE.test(x) && !isClaimed(dirname(x)))) {
|
|
41400
|
-
const
|
|
41401
|
-
|
|
41402
|
-
try {
|
|
41403
|
-
fm = splitFrontmatter(text).data;
|
|
41404
|
-
} catch (err) {
|
|
41405
|
-
problems.push({ path: p, message: `frontmatter isn't valid YAML: ${err.message}` });
|
|
41328
|
+
for (const p of paths.filter((x) => detect && AGENT_FILE.test(x) && !listed.has(x) && !isClaimed(dirname(x)))) {
|
|
41329
|
+
const fm = await readFrontmatter(p);
|
|
41330
|
+
if (!fm || typeof fm.description !== "string")
|
|
41406
41331
|
continue;
|
|
41407
|
-
|
|
41408
|
-
if (typeof fm.description !== "string")
|
|
41409
|
-
continue;
|
|
41410
|
-
const name = typeof fm.name === "string" && fm.name.trim() ? fm.name : basename(p).replace(/\.md$/, "");
|
|
41411
|
-
const skills = asList(fm.skills);
|
|
41412
|
-
const depends = skills.length ? { skills: Object.fromEntries(skills.map((s) => [s.includes("/") ? s : `${input2.namespace}/${slugify2(s)}`, "*"])) } : {};
|
|
41413
|
-
const asset = make(name, "agent", p, /* @__PURE__ */ new Map([["AGENT.md", p]]), {}, {
|
|
41414
|
-
description: fm.description,
|
|
41415
|
-
depends,
|
|
41416
|
-
agent: {
|
|
41417
|
-
system_prompt: "AGENT.md",
|
|
41418
|
-
model: typeof fm.model === "string" ? fm.model : void 0,
|
|
41419
|
-
tools: asList(fm.tools),
|
|
41420
|
-
subagents: []
|
|
41421
|
-
}
|
|
41422
|
-
});
|
|
41332
|
+
const asset = agentAsset(p, fm);
|
|
41423
41333
|
if (asset)
|
|
41424
41334
|
found.push(asset);
|
|
41425
41335
|
}
|
|
41426
|
-
for (const p of paths.filter((x) => TOOLSET_FILE.test(rel(root, x)) && !isClaimed(dirname(x)))) {
|
|
41336
|
+
for (const p of paths.filter((x) => detect && TOOLSET_FILE.test(rel(root, x)) && !listed.has(x) && !isClaimed(dirname(x)))) {
|
|
41427
41337
|
const dir = dirname(p);
|
|
41428
41338
|
const name = TOOLSET_FILE.exec(rel(root, p))[1] ?? input2.repoName;
|
|
41429
41339
|
const servers = toolsetServers2(await input2.read(p), p, problems);
|
|
@@ -41446,16 +41356,16 @@ async function detectAssets(input2) {
|
|
|
41446
41356
|
}
|
|
41447
41357
|
return { assets: [...byName.values()], problems };
|
|
41448
41358
|
}
|
|
41449
|
-
function toolsetServers2(text,
|
|
41359
|
+
function toolsetServers2(text, path18, problems) {
|
|
41450
41360
|
let doc;
|
|
41451
41361
|
try {
|
|
41452
41362
|
doc = JSON.parse(text ?? "");
|
|
41453
41363
|
} catch (err) {
|
|
41454
|
-
problems.push({ path:
|
|
41364
|
+
problems.push({ path: path18, message: `isn't valid JSON: ${err.message}` });
|
|
41455
41365
|
return null;
|
|
41456
41366
|
}
|
|
41457
41367
|
const out = [];
|
|
41458
|
-
for (const [name, s] of Object.entries(doc.mcpServers ?? {})) {
|
|
41368
|
+
for (const [name, s] of Object.entries(doc.mcpServers ?? doc.servers ?? {})) {
|
|
41459
41369
|
const http = s.type === "http" || s.type === "sse" || typeof s.url === "string" && !s.command;
|
|
41460
41370
|
const refs = (field) => {
|
|
41461
41371
|
const map2 = s[field] ?? {};
|
|
@@ -41464,7 +41374,7 @@ function toolsetServers2(text, path16, problems) {
|
|
|
41464
41374
|
const ref = String(v).replace(/\$\{([A-Za-z_][A-Za-z0-9_]*)(?::-[^}]*)?\}/g, "${env:$1}");
|
|
41465
41375
|
const plain = ref.replace(/^Bearer /, "");
|
|
41466
41376
|
if (!SECRET_REF.test(plain)) {
|
|
41467
|
-
problems.push({ path:
|
|
41377
|
+
problems.push({ path: path18, message: `${name}.${field}.${k} is a literal value. Use \${${k.toUpperCase().replace(/[^A-Z0-9]+/g, "_")}} or \${vault:path#key} so no secret lives in the repo.` });
|
|
41468
41378
|
return null;
|
|
41469
41379
|
}
|
|
41470
41380
|
res[k] = ref;
|
|
@@ -41484,7 +41394,7 @@ function toolsetServers2(text, path16, problems) {
|
|
|
41484
41394
|
});
|
|
41485
41395
|
}
|
|
41486
41396
|
if (!out.length) {
|
|
41487
|
-
problems.push({ path:
|
|
41397
|
+
problems.push({ path: path18, message: "has no mcpServers." });
|
|
41488
41398
|
return null;
|
|
41489
41399
|
}
|
|
41490
41400
|
return out;
|
|
@@ -41498,7 +41408,7 @@ function firstParagraph(md2) {
|
|
|
41498
41408
|
|
|
41499
41409
|
// src/resolve.ts
|
|
41500
41410
|
var import_semver2 = __toESM(require_semver2(), 1);
|
|
41501
|
-
async function resolveAll(
|
|
41411
|
+
async function resolveAll(api, opts) {
|
|
41502
41412
|
const ranges = /* @__PURE__ */ new Map();
|
|
41503
41413
|
const queue = [];
|
|
41504
41414
|
const want = (name, range, from) => {
|
|
@@ -41509,14 +41419,12 @@ async function resolveAll(api2, opts) {
|
|
|
41509
41419
|
};
|
|
41510
41420
|
for (const [name, range] of Object.entries(opts.roots)) want(name, range, null);
|
|
41511
41421
|
const channels = /* @__PURE__ */ new Map();
|
|
41512
|
-
const pins = /* @__PURE__ */ new Map();
|
|
41513
41422
|
for (const r of opts.arkRoots ?? []) {
|
|
41514
|
-
for (const src of r.sources) want(r.name, r.range ?? "*",
|
|
41423
|
+
for (const src of r.sources) want(r.name, r.range ?? "*", `ark:${src}`);
|
|
41515
41424
|
if (r.channel) channels.set(r.name, r.channel);
|
|
41516
|
-
if (r.digest && r.range) pins.set(r.name, { version: r.range, digest: r.digest, sources: r.sources });
|
|
41517
41425
|
}
|
|
41518
41426
|
const out = /* @__PURE__ */ new Map();
|
|
41519
|
-
const key = await signingKey(
|
|
41427
|
+
const key = await signingKey(api);
|
|
41520
41428
|
while (queue.length) {
|
|
41521
41429
|
const name = queue.shift();
|
|
41522
41430
|
const reqs = ranges.get(name);
|
|
@@ -41525,22 +41433,10 @@ async function resolveAll(api2, opts) {
|
|
|
41525
41433
|
prev.lock.required_by = requiredBy(reqs);
|
|
41526
41434
|
continue;
|
|
41527
41435
|
}
|
|
41528
|
-
const
|
|
41529
|
-
|
|
41530
|
-
const clash = reqs.find((r) => !satisfies(pin.version, r.range));
|
|
41531
|
-
if (clash) {
|
|
41532
|
-
throw new CliError(`${name}: ${pin.sources.join(", ")} pins ${pin.version}, but ${clash.from ?? "yarkr.json"} wants ${clash.range}.`, "A collection pins exact releases. Relax the other range, or use another version of the collection.");
|
|
41533
|
-
}
|
|
41534
|
-
}
|
|
41535
|
-
const version2 = pin?.version ?? await pickVersion(api2, name, reqs, { ...opts, channel: channels.get(name) ?? opts.channel });
|
|
41536
|
-
const bundle = await api2.bundle(name, version2);
|
|
41436
|
+
const version2 = await pickVersion(api, name, reqs, { ...opts, channel: channels.get(name) ?? opts.channel });
|
|
41437
|
+
const bundle = await api.bundle(name, version2, { sync: true });
|
|
41537
41438
|
const pkg = verifyBundle(bundle, key, opts.requireSignatures ?? false);
|
|
41538
|
-
if (
|
|
41539
|
-
throw new CliError(
|
|
41540
|
-
`${name}@${version2} doesn't match the content hash ${pin.sources.join(", ")} pinned (${pin.digest.slice(0, 12)}\u2026, got ${bundle.content_hash.slice(0, 12)}\u2026).`,
|
|
41541
|
-
"Nothing was written. Report this to your Yarkr admin."
|
|
41542
|
-
);
|
|
41543
|
-
}
|
|
41439
|
+
if (bundle.yanked) ui.warn(`${name}@${version2} was yanked: ${bundle.yanked.reason}. Run \`yarkr update ${name}\` to move off it.`);
|
|
41544
41440
|
out.set(name, {
|
|
41545
41441
|
pkg,
|
|
41546
41442
|
lock: {
|
|
@@ -41562,14 +41458,14 @@ async function resolveAll(api2, opts) {
|
|
|
41562
41458
|
}
|
|
41563
41459
|
var satisfies = (v, range) => range === "*" || range === "latest" || import_semver2.default.satisfies(v, range, { includePrerelease: true });
|
|
41564
41460
|
var requiredBy = (reqs) => [...new Set(reqs.map((r) => r.from).filter((f) => !!f))].sort();
|
|
41565
|
-
async function pickVersion(
|
|
41461
|
+
async function pickVersion(api, name, reqs, opts) {
|
|
41566
41462
|
const locked = opts.lock?.packages[name];
|
|
41567
41463
|
const updating = opts.update === true || opts.update?.has(name);
|
|
41568
41464
|
if (locked && !updating && reqs.every((r) => satisfies(locked.version, r.range))) return locked.version;
|
|
41569
41465
|
const ranges = reqs.map((r) => r.range).filter((r) => r !== "*" && r !== "latest");
|
|
41570
41466
|
const combined = ranges.length ? ranges.join(" ") : void 0;
|
|
41571
41467
|
try {
|
|
41572
|
-
const rel2 = await
|
|
41468
|
+
const rel2 = await api.resolve(name, { channel: opts.channel, range: combined });
|
|
41573
41469
|
if (!reqs.every((r) => satisfies(rel2.version, r.range))) throw new Error("unsatisfied");
|
|
41574
41470
|
return rel2.version;
|
|
41575
41471
|
} catch (err) {
|
|
@@ -41583,9 +41479,9 @@ async function pickVersion(api2, name, reqs, opts) {
|
|
|
41583
41479
|
throw err;
|
|
41584
41480
|
}
|
|
41585
41481
|
}
|
|
41586
|
-
async function signingKey(
|
|
41482
|
+
async function signingKey(api) {
|
|
41587
41483
|
try {
|
|
41588
|
-
return await
|
|
41484
|
+
return await api.signingKey();
|
|
41589
41485
|
} catch {
|
|
41590
41486
|
return null;
|
|
41591
41487
|
}
|
|
@@ -41622,8 +41518,8 @@ function verifyBundle(b, key, requireSignature) {
|
|
|
41622
41518
|
return { manifest: b.manifest, files, content_hash: b.content_hash };
|
|
41623
41519
|
}
|
|
41624
41520
|
var TEXT_EXT = /\.(md|mdc|mdx|markdown|txt|ya?ml|json|toml|py|sh|bash|js|mjs|cjs|ts|tsx|csv|html|css|xml|sql|rb|go|rs|java|ini|cfg|env)$/i;
|
|
41625
|
-
function looksText(
|
|
41626
|
-
if (TEXT_EXT.test(
|
|
41521
|
+
function looksText(path18, bytes) {
|
|
41522
|
+
if (TEXT_EXT.test(path18)) return true;
|
|
41627
41523
|
const n = Math.min(bytes.length, 4096);
|
|
41628
41524
|
for (let i = 0; i < n; i++) if (bytes[i] === 0) return false;
|
|
41629
41525
|
try {
|
|
@@ -41635,6 +41531,16 @@ function looksText(path16, bytes) {
|
|
|
41635
41531
|
}
|
|
41636
41532
|
|
|
41637
41533
|
// src/sync.ts
|
|
41534
|
+
async function loadArks(api, arks, signedIn) {
|
|
41535
|
+
if (!arks) return { ark: null, publicArks: [] };
|
|
41536
|
+
if (arks === "auto") return { ark: signedIn ? await api.myArk() : null, publicArks: [] };
|
|
41537
|
+
const all = signedIn ? await api.myArk() : null;
|
|
41538
|
+
const mine = arks.filter((r) => r === "@me" || all?.arks.some((a) => a.ref === r));
|
|
41539
|
+
if (!signedIn && arks.includes("@me")) throw new CliError("@me is your personal ark: sign in to sync it.", 'Run `yarkr login`, or drop @me from "arks".');
|
|
41540
|
+
const publicArks2 = [];
|
|
41541
|
+
for (const ref of arks.filter((r) => !mine.includes(r))) publicArks2.push(await api.ark(ref, { sync: true }));
|
|
41542
|
+
return { ark: mine.length ? await api.myArk(mine) : null, publicArks: publicArks2 };
|
|
41543
|
+
}
|
|
41638
41544
|
var hashOf = (c) => sha256(c);
|
|
41639
41545
|
async function readMaybe(p) {
|
|
41640
41546
|
try {
|
|
@@ -41643,35 +41549,25 @@ async function readMaybe(p) {
|
|
|
41643
41549
|
return null;
|
|
41644
41550
|
}
|
|
41645
41551
|
}
|
|
41646
|
-
async function planSync(
|
|
41552
|
+
async function planSync(api, opts) {
|
|
41647
41553
|
const { config: config2 } = opts;
|
|
41648
41554
|
const harnesses = opts.harnesses ?? config2.harnesses;
|
|
41649
41555
|
if (!harnesses.length) throw new CliError("No harnesses configured.", "Add some to yarkr.json, e.g. `yarkr init --harness claude-code codex`.");
|
|
41650
41556
|
const unknown2 = harnesses.filter((h) => !config2.harnesses.includes(h));
|
|
41651
41557
|
if (unknown2.length) throw new CliError(`${unknown2.join(", ")} isn't in yarkr.json's harnesses.`, "Add it there first so the lockfile can track its files.");
|
|
41652
41558
|
const warnings = [];
|
|
41653
|
-
const ark
|
|
41559
|
+
const { ark, publicArks: publicArks2 } = await loadArks(api, config2.arks, opts.signedIn ?? true);
|
|
41560
|
+
const items = [...ark?.items ?? [], ...publicArks2.flatMap((a) => a.items.map((i) => ({ ...i, sources: [a.ref] })))];
|
|
41654
41561
|
const arkRoots = [];
|
|
41655
41562
|
const excluded = new Set(config2.exclude ?? []);
|
|
41656
|
-
for (const it of
|
|
41563
|
+
for (const it of items) {
|
|
41657
41564
|
if (excluded.has(it.package)) {
|
|
41658
41565
|
if (!it.required) continue;
|
|
41659
41566
|
warnings.push(`${it.package} is required by ${it.sources.join(", ")}; "exclude" can't drop it.`);
|
|
41660
41567
|
}
|
|
41661
41568
|
arkRoots.push({ name: it.package, range: it.range, channel: it.channel, sources: it.sources });
|
|
41662
41569
|
}
|
|
41663
|
-
const
|
|
41664
|
-
for (const ref of config2.collections ?? []) {
|
|
41665
|
-
const c = await api2.readCollection(ref);
|
|
41666
|
-
collections.push(c);
|
|
41667
|
-
for (const it of c.items) {
|
|
41668
|
-
const same = arkRoots.find((r) => r.name === it.package && r.digest);
|
|
41669
|
-
if (same && same.range !== it.version) throw new CliError(`${it.package}: ${same.sources.join(", ")} pins ${same.range}, but ${c.ref} pins ${it.version}.`, "Use versions of these collections that agree, or drop one.");
|
|
41670
|
-
if (same) same.sources.push(c.ref);
|
|
41671
|
-
else arkRoots.push({ name: it.package, range: it.version, channel: null, sources: [c.ref], digest: it.digest, via: "collection" });
|
|
41672
|
-
}
|
|
41673
|
-
}
|
|
41674
|
-
const resolved = await resolveAll(api2, {
|
|
41570
|
+
const resolved = await resolveAll(api, {
|
|
41675
41571
|
channel: config2.channel,
|
|
41676
41572
|
roots: config2.packages,
|
|
41677
41573
|
arkRoots,
|
|
@@ -41679,13 +41575,13 @@ async function planSync(api2, opts) {
|
|
|
41679
41575
|
update: opts.update,
|
|
41680
41576
|
requireSignatures: opts.requireSignatures
|
|
41681
41577
|
});
|
|
41682
|
-
for (const it of
|
|
41578
|
+
for (const it of items) {
|
|
41683
41579
|
const r = resolved.get(it.package);
|
|
41684
41580
|
if (r && it.config.servers) r.pkg = withServerOverrides(r.pkg, it.config.servers);
|
|
41685
41581
|
}
|
|
41686
41582
|
const packages = [...resolved.values()].map((r) => r.pkg);
|
|
41687
41583
|
for (const m of config2.mcp ?? []) packages.push(connectionPackage(connectionFor(opts.server, m)));
|
|
41688
|
-
const base = config2.scope === "user" ? opts.home ??
|
|
41584
|
+
const base = config2.scope === "user" ? opts.home ?? os4.homedir() : opts.dir;
|
|
41689
41585
|
const prevOutputs = opts.lock?.outputs ?? {};
|
|
41690
41586
|
const outputs = {};
|
|
41691
41587
|
for (const [h, o] of Object.entries(prevOutputs)) if (!harnesses.includes(h) && config2.harnesses.includes(h)) outputs[h] = o;
|
|
@@ -41763,11 +41659,10 @@ async function planSync(api2, opts) {
|
|
|
41763
41659
|
scope: config2.scope,
|
|
41764
41660
|
packages: Object.fromEntries([...resolved.entries()].map(([n, r]) => [n, r.lock])),
|
|
41765
41661
|
outputs,
|
|
41766
|
-
...ark ? { arks: ark
|
|
41767
|
-
...collections.length ? { collections: collections.map((c) => c.ref) } : {}
|
|
41662
|
+
...ark || publicArks2.length ? { arks: [...ark?.arks.map((a) => a.ref) ?? [], ...publicArks2.map((a) => a.ref)] } : {}
|
|
41768
41663
|
};
|
|
41769
41664
|
const lockChanged = !opts.lock || stringifyLock(lock) !== stringifyLock(opts.lock);
|
|
41770
|
-
return { resolved, packages, changes, conflicts, kept, notes, warnings, ark,
|
|
41665
|
+
return { resolved, packages, changes, conflicts, kept, notes, warnings, ark, publicArks: publicArks2, lock, lockChanged, base };
|
|
41771
41666
|
}
|
|
41772
41667
|
function withServerOverrides(pkg, overrides) {
|
|
41773
41668
|
const ts = pkg.manifest.toolset;
|
|
@@ -41915,46 +41810,45 @@ async function init2(opts) {
|
|
|
41915
41810
|
async function context(flags = {}) {
|
|
41916
41811
|
const cwd = process.cwd();
|
|
41917
41812
|
const conn = await resolveConnection({ dir: cwd, registry: flags.registry });
|
|
41918
|
-
const
|
|
41813
|
+
const api = new Api(conn);
|
|
41919
41814
|
const project = flags.user ? null : await loadProjectConfig(cwd, { required: false });
|
|
41920
|
-
if (project) return { dir: cwd, config: project, conn, api
|
|
41815
|
+
if (project) return { dir: cwd, config: project, conn, api, lock: await loadLock(cwd), userMode: false };
|
|
41921
41816
|
const dir = userStateDir();
|
|
41922
41817
|
let config2 = await loadProjectConfig(dir, { required: false });
|
|
41923
41818
|
if (!config2) {
|
|
41924
|
-
const
|
|
41925
|
-
config2 = { channel: "stable", scope: "user", harnesses:
|
|
41819
|
+
const detected2 = detectHarnesses2(os5.homedir());
|
|
41820
|
+
config2 = { channel: "stable", scope: "user", harnesses: detected2.length ? detected2 : ["claude-code"], packages: {}, arks: "auto" };
|
|
41926
41821
|
await mkdir3(dir, { recursive: true });
|
|
41927
41822
|
await saveProjectConfig(dir, config2);
|
|
41928
41823
|
ui.info(`No ${CONFIG_FILE} here, so yarkr installs your arks into your home directory (${config2.harnesses.join(", ")}). Settings: ${path5.join(dir, CONFIG_FILE)}.`);
|
|
41929
41824
|
}
|
|
41930
|
-
return { dir, config: config2, conn, api
|
|
41825
|
+
return { dir, config: config2, conn, api, lock: await loadLock(dir), userMode: true };
|
|
41931
41826
|
}
|
|
41932
|
-
async function sync(flags, update2,
|
|
41933
|
-
const { dir, config: config2, conn, api
|
|
41827
|
+
async function sync(flags, update2, arkRefs = []) {
|
|
41828
|
+
const { dir, config: config2, conn, api, lock, userMode } = await context(flags);
|
|
41934
41829
|
const harnesses = parseHarnesses(flags.harness);
|
|
41935
|
-
if (
|
|
41936
|
-
for (const ref of
|
|
41937
|
-
|
|
41938
|
-
|
|
41939
|
-
|
|
41940
|
-
config2.collections = [...(config2.collections ?? []).filter((c) => c !== base && !c.startsWith(`${base}@`)), ref];
|
|
41830
|
+
if (arkRefs.length) {
|
|
41831
|
+
for (const ref of arkRefs) {
|
|
41832
|
+
if (ref !== "@me" && !/^[a-z0-9][a-z0-9-]*\/[a-z0-9][a-z0-9-]*$/.test(ref)) throw new CliError(`"${ref}" isn't an ark.`, "Arks look like <org>/<ark>, e.g. acme/starter; @me is your personal ark.");
|
|
41833
|
+
const listed = Array.isArray(config2.arks) ? config2.arks : config2.arks === "auto" && conn.token ? (await api.myArk()).arks.map((a) => a.ref) : [];
|
|
41834
|
+
config2.arks = [...listed.filter((a) => a !== ref), ref];
|
|
41941
41835
|
}
|
|
41942
41836
|
for (const h of harnesses ?? []) if (!config2.harnesses.includes(h)) config2.harnesses.push(h);
|
|
41943
41837
|
}
|
|
41944
41838
|
const runConfig = !conn.token && config2.arks === "auto" ? { ...config2, arks: void 0 } : config2;
|
|
41945
|
-
if (runConfig !== config2 && userMode) ui.info("Not signed in, so only
|
|
41946
|
-
const opts = { dir, config: runConfig, lock, server: conn.server, harnesses, update: update2, requireSignatures: flags.requireSignatures };
|
|
41947
|
-
const plan = await planSync(
|
|
41948
|
-
if (
|
|
41839
|
+
if (runConfig !== config2 && userMode) ui.info("Not signed in, so only packages and public arks are synced. `yarkr login` adds your arks.");
|
|
41840
|
+
const opts = { dir, config: runConfig, lock, server: conn.server, harnesses, update: update2, requireSignatures: flags.requireSignatures, signedIn: !!conn.token };
|
|
41841
|
+
const plan = await planSync(api, opts);
|
|
41842
|
+
if (arkRefs.length && !flags.dryRun && !flags.check) await saveProjectConfig(dir, config2);
|
|
41949
41843
|
if (plan.ark) ui.info(plan.ark.arks.length ? `Arks: ${plan.ark.arks.map((a) => a.ref).join(", ")}` : "No arks give you anything yet.");
|
|
41950
|
-
for (const
|
|
41844
|
+
for (const a of plan.publicArks) ui.info(`Public ark ${a.ref}${a.description ? ui.dim(` \xB7 ${a.description}`) : ""}`);
|
|
41951
41845
|
for (const [name, r] of [...plan.resolved.entries()].sort(([a], [b]) => a < b ? -1 : 1)) {
|
|
41952
41846
|
const prev = lock?.packages[name]?.version;
|
|
41953
|
-
const via = r.lock.required_by.length ? ui.dim(` (via ${r.lock.required_by.map((v) => v.replace(/^
|
|
41847
|
+
const via = r.lock.required_by.length ? ui.dim(` (via ${r.lock.required_by.map((v) => v.replace(/^ark:/, "ark ")).join(", ")})`) : "";
|
|
41954
41848
|
const move = prev && prev !== r.lock.version ? `${ui.dim(prev)} \u2192 ${ui.bold(r.lock.version)}` : ui.bold(r.lock.version);
|
|
41955
41849
|
ui.step(`${name} ${move}${via}`);
|
|
41956
41850
|
}
|
|
41957
|
-
if (!plan.resolved.size && !plan.ark && !plan.
|
|
41851
|
+
if (!plan.resolved.size && !plan.ark && !plan.publicArks.length) ui.info(`No packages in ${CONFIG_FILE}. Add one with \`yarkr add <namespace/name>\`.`);
|
|
41958
41852
|
for (const w of plan.warnings) ui.warn(w);
|
|
41959
41853
|
printChanges(plan.changes);
|
|
41960
41854
|
for (const k of plan.kept) ui.warn(flags.force ? `${k.path}: discarding your local edits (--force).` : `${k.path}: kept your local edits. \`yarkr diff\` shows them; open a pull request in the package's repo to send them upstream.`);
|
|
@@ -41997,16 +41891,16 @@ var splitSpec = (spec) => {
|
|
|
41997
41891
|
return at > 0 ? { name: spec.slice(0, at), range: spec.slice(at + 1) } : { name: spec, range: "" };
|
|
41998
41892
|
};
|
|
41999
41893
|
async function add(specs, flags) {
|
|
42000
|
-
const { dir, config: config2, conn, api
|
|
41894
|
+
const { dir, config: config2, conn, api, userMode } = await context(flags);
|
|
42001
41895
|
const added = [];
|
|
42002
41896
|
for (const spec of specs) {
|
|
42003
41897
|
let { name, range } = splitSpec(spec);
|
|
42004
41898
|
if (!PackageName.safeParse(name).success) throw new CliError(`"${name}" isn't a package name.`, "Use namespace/name, e.g. finance/invoice-extraction.");
|
|
42005
41899
|
if (!range) {
|
|
42006
|
-
const rel2 = await
|
|
41900
|
+
const rel2 = await api.resolve(name, { channel: config2.channel });
|
|
42007
41901
|
range = `^${rel2.version}`;
|
|
42008
41902
|
}
|
|
42009
|
-
if (userMode && conn.token) await
|
|
41903
|
+
if (userMode && conn.token) await api.addPersonal(name, range);
|
|
42010
41904
|
else config2.packages[name] = range;
|
|
42011
41905
|
added.push(`${name}@${range}`);
|
|
42012
41906
|
}
|
|
@@ -42017,38 +41911,38 @@ async function add(specs, flags) {
|
|
|
42017
41911
|
if (!flags.noSync) await sync(flags, new Set(specs.map((s) => splitSpec(s).name)));
|
|
42018
41912
|
}
|
|
42019
41913
|
async function remove(names, flags) {
|
|
42020
|
-
const { dir, config: config2, conn, api
|
|
42021
|
-
const
|
|
42022
|
-
|
|
42023
|
-
|
|
42024
|
-
return base ? (config2.collections ?? []).filter((c) => c === base || c.startsWith(`${base}@`)) : [];
|
|
42025
|
-
};
|
|
42026
|
-
const needsArk = names.some((n) => !(n in config2.packages) && !syncedCollection(n).length);
|
|
42027
|
-
const ark = needsArk && config2.arks && (conn.token || config2.arks !== "auto") ? await api2.myArk(config2.arks === "auto" ? void 0 : config2.arks) : null;
|
|
41914
|
+
const { dir, config: config2, conn, api, lock, userMode } = await context(flags);
|
|
41915
|
+
const listedArk = (n) => Array.isArray(config2.arks) && config2.arks.includes(n);
|
|
41916
|
+
const needsArk = names.some((n) => !(n in config2.packages) && !listedArk(n));
|
|
41917
|
+
const ark = needsArk && config2.arks && conn.token ? await api.myArk(config2.arks === "auto" ? void 0 : await ownArks(api, config2.arks)) : null;
|
|
42028
41918
|
const personalRef = ark?.arks.find((a) => a.kind === "personal")?.ref;
|
|
42029
41919
|
for (const n of names) {
|
|
42030
41920
|
if (n in config2.packages) {
|
|
42031
41921
|
delete config2.packages[n];
|
|
42032
41922
|
continue;
|
|
42033
41923
|
}
|
|
42034
|
-
|
|
42035
|
-
|
|
42036
|
-
config2.collections = config2.collections.filter((c) => !cols.includes(c));
|
|
42037
|
-
if (!config2.collections.length) delete config2.collections;
|
|
41924
|
+
if (listedArk(n)) {
|
|
41925
|
+
config2.arks = config2.arks.filter((a) => a !== n);
|
|
42038
41926
|
continue;
|
|
42039
41927
|
}
|
|
42040
41928
|
const item = ark?.items.find((i) => i.package === n);
|
|
42041
41929
|
if (!item) {
|
|
42042
41930
|
const via = lock?.packages[n]?.required_by ?? [];
|
|
42043
|
-
|
|
41931
|
+
const fromPublicArk = via.some((v) => v.startsWith("ark:") && !ark?.arks.some((a) => `ark:${a.ref}` === v));
|
|
41932
|
+
if (fromPublicArk) {
|
|
41933
|
+
if (userMode) throw new CliError(`${n} comes from a public ark (${via.join(", ")}).`, `Remove the ark itself, or list the package under "exclude" if it's optional.`);
|
|
41934
|
+
config2.exclude = [.../* @__PURE__ */ new Set([...config2.exclude ?? [], n])];
|
|
41935
|
+
continue;
|
|
41936
|
+
}
|
|
41937
|
+
throw new CliError(`${n} isn't a direct dependency, an ark or an ark item here.`, via.length ? `It's installed because ${via.join(", ")} needs it.` : void 0);
|
|
42044
41938
|
}
|
|
42045
41939
|
const orgSources = item.sources.filter((src) => src !== personalRef);
|
|
42046
41940
|
if (orgSources.length && item.required) {
|
|
42047
41941
|
throw new CliError(`${n} is required by ${orgSources.join(", ")}.`, "Only optional ark items can be removed. Ask the ark's admin.");
|
|
42048
41942
|
}
|
|
42049
|
-
if (personalRef && item.sources.includes(personalRef)) await
|
|
41943
|
+
if (personalRef && item.sources.includes(personalRef)) await api.removePersonal(n);
|
|
42050
41944
|
for (const src of orgSources) {
|
|
42051
|
-
if (userMode) await
|
|
41945
|
+
if (userMode) await api.exclude(src, n, true);
|
|
42052
41946
|
else config2.exclude = [.../* @__PURE__ */ new Set([...config2.exclude ?? [], n])];
|
|
42053
41947
|
}
|
|
42054
41948
|
}
|
|
@@ -42057,8 +41951,8 @@ async function remove(names, flags) {
|
|
|
42057
41951
|
if (!flags.noSync) await sync(flags);
|
|
42058
41952
|
}
|
|
42059
41953
|
async function showArk(refs, opts) {
|
|
42060
|
-
const
|
|
42061
|
-
const eff = await
|
|
41954
|
+
const api = new Api(await resolveConnection({ dir: process.cwd() }));
|
|
41955
|
+
const eff = await api.myArk(refs.length ? refs : void 0);
|
|
42062
41956
|
if (opts.json) return console.log(JSON.stringify(eff, null, 2));
|
|
42063
41957
|
if (!eff.arks.length) return ui.info("No arks give you anything yet. Ask an org admin, or add your own with `yarkr add` outside a project.");
|
|
42064
41958
|
ui.heading("Your arks");
|
|
@@ -42071,7 +41965,18 @@ async function showArk(refs, opts) {
|
|
|
42071
41965
|
);
|
|
42072
41966
|
} else ui.info("Your arks are empty.");
|
|
42073
41967
|
if (eff.excluded.length) ui.step(`Excluded by you: ${eff.excluded.map((e) => `${e.package} (${e.ark})`).join(", ")}`);
|
|
42074
|
-
|
|
41968
|
+
}
|
|
41969
|
+
async function publicArks(opts) {
|
|
41970
|
+
const api = new Api(await resolveConnection({ dir: process.cwd() }));
|
|
41971
|
+
const arks = await api.publicArks();
|
|
41972
|
+
if (opts.json) return console.log(JSON.stringify(arks, null, 2));
|
|
41973
|
+
if (!arks.length) return ui.info("No public arks yet. An org admin makes one public on the ark's page.");
|
|
41974
|
+
ui.table(arks.map((a) => [ui.bold(a.ref), String(a.items.length), a.uses_30d === void 0 ? "\u2014" : String(a.uses_30d), a.description]), ["ark", "packages", "uses (30d)", "description"]);
|
|
41975
|
+
ui.step(`Install one with ${ui.code("yarkr sync <org>/<ark>")}, or connect it with ${ui.code("yarkr mcp add <org>/<ark>")}. No sign-in needed.`);
|
|
41976
|
+
}
|
|
41977
|
+
async function ownArks(api, refs) {
|
|
41978
|
+
const all = await api.myArk();
|
|
41979
|
+
return refs.filter((r) => r === "@me" || all.arks.some((a) => a.ref === r));
|
|
42075
41980
|
}
|
|
42076
41981
|
async function update(names, flags) {
|
|
42077
41982
|
return sync(flags, names.length ? new Set(names) : true);
|
|
@@ -42079,7 +41984,7 @@ async function update(names, flags) {
|
|
|
42079
41984
|
|
|
42080
41985
|
// src/commands/diff.ts
|
|
42081
41986
|
import { readFile as readFile4 } from "fs/promises";
|
|
42082
|
-
import
|
|
41987
|
+
import os6 from "os";
|
|
42083
41988
|
import path6 from "path";
|
|
42084
41989
|
|
|
42085
41990
|
// ../../node_modules/.pnpm/diff@8.0.4/node_modules/diff/libesm/diff/base.js
|
|
@@ -42182,16 +42087,16 @@ var Diff = class {
|
|
|
42182
42087
|
}
|
|
42183
42088
|
}
|
|
42184
42089
|
}
|
|
42185
|
-
addToPath(
|
|
42186
|
-
const last =
|
|
42090
|
+
addToPath(path18, added, removed, oldPosInc, options) {
|
|
42091
|
+
const last = path18.lastComponent;
|
|
42187
42092
|
if (last && !options.oneChangePerToken && last.added === added && last.removed === removed) {
|
|
42188
42093
|
return {
|
|
42189
|
-
oldPos:
|
|
42094
|
+
oldPos: path18.oldPos + oldPosInc,
|
|
42190
42095
|
lastComponent: { count: last.count + 1, added, removed, previousComponent: last.previousComponent }
|
|
42191
42096
|
};
|
|
42192
42097
|
} else {
|
|
42193
42098
|
return {
|
|
42194
|
-
oldPos:
|
|
42099
|
+
oldPos: path18.oldPos + oldPosInc,
|
|
42195
42100
|
lastComponent: { count: 1, added, removed, previousComponent: last }
|
|
42196
42101
|
};
|
|
42197
42102
|
}
|
|
@@ -42519,7 +42424,7 @@ async function diff(name, opts) {
|
|
|
42519
42424
|
const lock = await loadLock(dir);
|
|
42520
42425
|
if (!lock) throw new CliError("Nothing synced yet.", "Run `yarkr sync` first.");
|
|
42521
42426
|
if (name && !lock.packages[name]) throw new CliError(`${name} isn't in yarkr.lock.`);
|
|
42522
|
-
const base = config2.scope === "user" ?
|
|
42427
|
+
const base = config2.scope === "user" ? os6.homedir() : dir;
|
|
42523
42428
|
const edited = [];
|
|
42524
42429
|
for (const [harness, out] of Object.entries(lock.outputs)) {
|
|
42525
42430
|
for (const [p, meta3] of Object.entries(out.files)) {
|
|
@@ -42542,9 +42447,9 @@ async function diff(name, opts) {
|
|
|
42542
42447
|
for (const e of edited) console.log(e.path);
|
|
42543
42448
|
return edited;
|
|
42544
42449
|
}
|
|
42545
|
-
const
|
|
42546
|
-
const key = await
|
|
42547
|
-
const pkgs = await Promise.all(Object.entries(lock.packages).map(async ([n, l]) => verifyBundle(await
|
|
42450
|
+
const api = new Api(await resolveConnection({ dir }));
|
|
42451
|
+
const key = await api.signingKey().catch(() => null);
|
|
42452
|
+
const pkgs = await Promise.all(Object.entries(lock.packages).map(async ([n, l]) => verifyBundle(await api.bundle(n, l.version), key, false)));
|
|
42548
42453
|
for (const harness of new Set(edited.map((e) => e.harness))) {
|
|
42549
42454
|
const out = render(harness, { packages: pkgs, scope: config2.scope, layout: config2.layout?.[harness] });
|
|
42550
42455
|
for (const e of edited.filter((x) => x.harness === harness)) {
|
|
@@ -42565,15 +42470,16 @@ async function diff(name, opts) {
|
|
|
42565
42470
|
|
|
42566
42471
|
// src/commands/mcp.ts
|
|
42567
42472
|
async function mcpAdd(scopes, flags) {
|
|
42568
|
-
const { dir, config: config2, conn, api
|
|
42569
|
-
const me = conn.token ? await
|
|
42473
|
+
const { dir, config: config2, conn, api, userMode } = await context(flags);
|
|
42474
|
+
const me = conn.token ? await api.me().catch(() => null) : null;
|
|
42570
42475
|
for (const scope of scopes) {
|
|
42571
|
-
if (!isConnectionScope(scope)) throw new CliError(`"${scope}" isn't an MCP scope.`, "Use an org (acme), a team (acme/finance),
|
|
42572
|
-
const org = !["all", "public"].includes(scope)
|
|
42573
|
-
|
|
42574
|
-
|
|
42476
|
+
if (!isConnectionScope(scope)) throw new CliError(`"${scope}" isn't an MCP scope.`, "Use an org (acme), a team or public ark (acme/finance), all, or public.");
|
|
42477
|
+
const org = !["all", "public"].includes(scope) ? scope.split("/")[0] : null;
|
|
42478
|
+
const member = !!org && !!me?.orgs.some((o) => o.slug === org);
|
|
42479
|
+
const isPublic = !!org && !member && scope.includes("/") && await api.ark(scope).then((a) => a.public).catch(() => false);
|
|
42480
|
+
if (org && !member && !isPublic && (me || !scope.includes("/"))) {
|
|
42481
|
+
throw new CliError(`You aren't a member of ${org} on ${conn.server}${scope.includes("/") ? `, and ${scope} isn't a public ark` : ""}.`, `Your orgs: ${me?.orgs.map((o) => o.slug).join(", ") || "none"}.`);
|
|
42575
42482
|
}
|
|
42576
|
-
const isPublic = parseCollectionRef(scope) ? (await api2.readCollection(scope)).visibility === "public" : false;
|
|
42577
42483
|
const entry = { scope, ...flags.tokenEnv && !isPublic ? { token_env: flags.tokenEnv } : {}, ...isPublic ? { public: true } : {} };
|
|
42578
42484
|
config2.mcp = [...(config2.mcp ?? []).filter((m) => m.scope !== scope), entry];
|
|
42579
42485
|
}
|
|
@@ -42597,7 +42503,7 @@ async function mcpList(flags) {
|
|
|
42597
42503
|
const rows = (config2.mcp ?? []).map((m) => connectionFor(conn.server, m));
|
|
42598
42504
|
if (flags.json) return console.log(JSON.stringify(rows, null, 2));
|
|
42599
42505
|
if (!rows.length) {
|
|
42600
|
-
ui.info("No MCP connections. Add one with `yarkr mcp add <org>` (or `<org>/<
|
|
42506
|
+
ui.info("No MCP connections. Add one with `yarkr mcp add <org>` (or `<org>/<ark>`, `all`, `public`).");
|
|
42601
42507
|
return;
|
|
42602
42508
|
}
|
|
42603
42509
|
ui.table(
|
|
@@ -42620,94 +42526,6 @@ function printHints(server, added, harnesses, userMode) {
|
|
|
42620
42526
|
}
|
|
42621
42527
|
}
|
|
42622
42528
|
|
|
42623
|
-
// src/commands/collection.ts
|
|
42624
|
-
var api = async () => new Api(await resolveConnection({ dir: process.cwd() }));
|
|
42625
|
-
function visibility(v) {
|
|
42626
|
-
if (v === void 0) return void 0;
|
|
42627
|
-
const r = CollectionVisibility.safeParse(v);
|
|
42628
|
-
if (!r.success) throw new CliError(`"${v}" isn't a visibility.`, "Use private (only you), org (members of --org) or public (anyone, no sign-in).");
|
|
42629
|
-
return r.data;
|
|
42630
|
-
}
|
|
42631
|
-
var audience = (c) => c.visibility === "org" ? `org ${c.org}` : c.visibility;
|
|
42632
|
-
function printCollection(c) {
|
|
42633
|
-
ui.heading(`${c.ref} ${ui.dim(`(${audience(c)})`)}${c.description ? ui.dim(` \xB7 ${c.description}`) : ""}`);
|
|
42634
|
-
if (c.arks.length) ui.table(c.arks.map((a) => [ui.bold(a.ref), a.kind, a.public ? "public" : "", a.description]), ["ark", "kind", "", "description"]);
|
|
42635
|
-
else ui.info(`No arks yet. Add some with \`yarkr collection add ${c.name} <ark>\` (@me, <org>/<ark>, global/<ark>, or a public ark).`);
|
|
42636
|
-
console.log();
|
|
42637
|
-
if (c.versions.length) {
|
|
42638
|
-
ui.table(c.versions.map((v) => [ui.bold(`@${v.version}`), String(v.items), v.published_at.slice(0, 10), v.note]), ["version", "packages", "published", "note"]);
|
|
42639
|
-
} else ui.info(`Not published yet: \`yarkr collection publish ${c.name}\`.`);
|
|
42640
|
-
}
|
|
42641
|
-
function printRelease(r) {
|
|
42642
|
-
ui.heading(`${r.ref} ${ui.dim(`(${r.visibility}${r.version < r.latest ? `, latest is ${r.latest}` : ""})`)}${r.note ? ui.dim(` \xB7 ${r.note}`) : ""}`);
|
|
42643
|
-
if (!r.items.length) return ui.info("Empty.");
|
|
42644
|
-
ui.table(
|
|
42645
|
-
r.items.map((i) => [ui.bold(i.package), i.kind ?? "?", i.version, ui.dim(`${i.digest.slice(0, 12)}\u2026`), i.sources.join(", ")]),
|
|
42646
|
-
["package", "kind", "version", "digest", "from"]
|
|
42647
|
-
);
|
|
42648
|
-
}
|
|
42649
|
-
async function collectionList(opts) {
|
|
42650
|
-
const list = await (await api()).collections();
|
|
42651
|
-
if (opts.json) return console.log(JSON.stringify(list, null, 2));
|
|
42652
|
-
if (!list.length) return ui.info("No collections yet. Create one with `yarkr collection create <name>`.");
|
|
42653
|
-
ui.table(
|
|
42654
|
-
list.map((c) => [ui.bold(c.ref), audience(c), c.versions[0] ? `@${c.versions[0].version}` : ui.dim("unpublished"), String(c.arks.length), c.description]),
|
|
42655
|
-
["collection", "visibility", "latest", "arks", "description"]
|
|
42656
|
-
);
|
|
42657
|
-
}
|
|
42658
|
-
async function collectionShow(ref, opts) {
|
|
42659
|
-
const client = await api();
|
|
42660
|
-
if (ref.startsWith("@")) {
|
|
42661
|
-
const r = await client.readCollection(ref);
|
|
42662
|
-
return opts.json ? console.log(JSON.stringify(r, null, 2)) : printRelease(r);
|
|
42663
|
-
}
|
|
42664
|
-
const c = await client.collection(ref);
|
|
42665
|
-
if (opts.json) return console.log(JSON.stringify(c, null, 2));
|
|
42666
|
-
printCollection(c);
|
|
42667
|
-
}
|
|
42668
|
-
async function collectionCreate(name, opts) {
|
|
42669
|
-
const v = opts.public ? "public" : visibility(opts.visibility) ?? (opts.org ? "org" : "private");
|
|
42670
|
-
const c = await (await api()).createCollection({ name, description: opts.description ?? "", visibility: v, ...opts.org ? { org: opts.org } : {} });
|
|
42671
|
-
ui.ok(`Created ${c.ref} (${audience(c)}).`);
|
|
42672
|
-
ui.step(`Add arks: ${ui.code(`yarkr collection add ${name} @me <org>/<ark> \u2026`)}, then ${ui.code(`yarkr collection publish ${name}`)}.`);
|
|
42673
|
-
}
|
|
42674
|
-
async function collectionEdit(name, opts) {
|
|
42675
|
-
const v = opts.public ? "public" : visibility(opts.visibility) ?? (opts.org ? "org" : void 0);
|
|
42676
|
-
if (v === void 0 && opts.description === void 0) throw new CliError("Nothing to change.", "Pass --visibility, --org, --public or --description.");
|
|
42677
|
-
const c = await (await api()).updateCollection(name, { ...opts.description !== void 0 ? { description: opts.description } : {}, ...v ? { visibility: v } : {}, ...opts.org ? { org: opts.org } : {} });
|
|
42678
|
-
ui.ok(`Updated ${c.ref} (${audience(c)}).`);
|
|
42679
|
-
}
|
|
42680
|
-
async function collectionDelete(name) {
|
|
42681
|
-
await (await api()).deleteCollection(name);
|
|
42682
|
-
ui.ok(`Deleted collection ${name}. Its published versions are gone too.`);
|
|
42683
|
-
}
|
|
42684
|
-
async function collectionAdd(name, refs) {
|
|
42685
|
-
const client = await api();
|
|
42686
|
-
let c;
|
|
42687
|
-
for (const ref of refs) c = await client.addCollectionArk(name, ref);
|
|
42688
|
-
ui.ok(`Added ${refs.join(", ")} to ${c.ref}. Publish to make it part of a version.`);
|
|
42689
|
-
}
|
|
42690
|
-
async function collectionRemove(name, refs) {
|
|
42691
|
-
const client = await api();
|
|
42692
|
-
let c;
|
|
42693
|
-
for (const ref of refs) c = await client.removeCollectionArk(name, ref);
|
|
42694
|
-
ui.ok(`Removed ${refs.join(", ")} from ${c.ref}. Publish to make it part of a version.`);
|
|
42695
|
-
}
|
|
42696
|
-
async function collectionPublish(name, opts) {
|
|
42697
|
-
const r = await (await api()).publishCollection(name, opts.message ?? "");
|
|
42698
|
-
if (opts.json) return console.log(JSON.stringify(r, null, 2));
|
|
42699
|
-
if (r.unchanged) ui.info(`Nothing changed since ${r.ref}.`);
|
|
42700
|
-
else ui.ok(`Published ${r.ref}.`);
|
|
42701
|
-
printRelease(r);
|
|
42702
|
-
ui.step(`Use it: ${ui.code(`yarkr sync ${r.collection}`)} (latest) or ${ui.code(`yarkr sync ${r.ref}`)}, or ${ui.code(`yarkr mcp add ${r.collection}`)}.`);
|
|
42703
|
-
}
|
|
42704
|
-
async function collectionArks(opts) {
|
|
42705
|
-
const list = await (await api()).publicArks();
|
|
42706
|
-
if (opts.json) return console.log(JSON.stringify(list, null, 2));
|
|
42707
|
-
if (!list.length) return ui.info("No public arks yet.");
|
|
42708
|
-
ui.table(list.map((a) => [ui.bold(a.ref), String(a.items.length), a.description]), ["ark", "packages", "description"]);
|
|
42709
|
-
}
|
|
42710
|
-
|
|
42711
42529
|
// src/commands/eval.ts
|
|
42712
42530
|
var import_ajv2 = __toESM(require_ajv(), 1);
|
|
42713
42531
|
import { existsSync as existsSync7 } from "fs";
|
|
@@ -42735,9 +42553,6 @@ function evalEnvFromProcess(env = process.env) {
|
|
|
42735
42553
|
anthropicApiKey: nonEmpty(env.ANTHROPIC_API_KEY),
|
|
42736
42554
|
openaiApiKey: nonEmpty(env.OPENAI_API_KEY),
|
|
42737
42555
|
judgeModel: nonEmpty(env.JUDGE_MODEL) ?? "claude-sonnet-5",
|
|
42738
|
-
customHttpUrl: nonEmpty(env.EVAL_CUSTOM_HTTP_URL),
|
|
42739
|
-
customHttpToken: nonEmpty(env.EVAL_CUSTOM_HTTP_TOKEN),
|
|
42740
|
-
customHttpVersion: nonEmpty(env.EVAL_CUSTOM_HTTP_VERSION),
|
|
42741
42556
|
opencodeProvider: nonEmpty(env.EVAL_OPENCODE_PROVIDER),
|
|
42742
42557
|
claudeAllowedTools: nonEmpty(env.EVAL_CLAUDE_ALLOWED_TOOLS),
|
|
42743
42558
|
extraSecrets: { YARKR_TOKEN: nonEmpty(env.YARKR_TOKEN) },
|
|
@@ -42806,7 +42621,6 @@ function harnessAccessEnv(harness, env) {
|
|
|
42806
42621
|
};
|
|
42807
42622
|
switch (harness) {
|
|
42808
42623
|
case "claude-code":
|
|
42809
|
-
case "claude-cowork":
|
|
42810
42624
|
if (gw) {
|
|
42811
42625
|
out.ANTHROPIC_BASE_URL = gw.url;
|
|
42812
42626
|
out.ANTHROPIC_AUTH_TOKEN = gw.token;
|
|
@@ -42849,7 +42663,6 @@ function secretsOf(env) {
|
|
|
42849
42663
|
[env.inferenceTokenName ?? "INFERENCE_API_TOKEN"]: env.inferenceToken,
|
|
42850
42664
|
ANTHROPIC_API_KEY: env.anthropicApiKey,
|
|
42851
42665
|
OPENAI_API_KEY: env.openaiApiKey,
|
|
42852
|
-
EVAL_CUSTOM_HTTP_TOKEN: env.customHttpToken,
|
|
42853
42666
|
...env.extraSecrets
|
|
42854
42667
|
};
|
|
42855
42668
|
return Object.fromEntries(Object.entries(all).filter((e) => typeof e[1] === "string" && e[1].length >= 8));
|
|
@@ -42858,11 +42671,10 @@ async function nativeRequirements(harness, env, onPath2) {
|
|
|
42858
42671
|
const missing = [];
|
|
42859
42672
|
const gw = gatewayOf(env);
|
|
42860
42673
|
const access2 = "INFERENCE_API_URL + INFERENCE_API_TOKEN";
|
|
42861
|
-
if (gw && !gw.token
|
|
42674
|
+
if (gw && !gw.token)
|
|
42862
42675
|
missing.push("INFERENCE_API_TOKEN (or API_TOKEN), since INFERENCE_API_URL is set");
|
|
42863
42676
|
switch (harness) {
|
|
42864
42677
|
case "claude-code":
|
|
42865
|
-
case "claude-cowork":
|
|
42866
42678
|
if (!await onPath2("claude"))
|
|
42867
42679
|
missing.push("the `claude` CLI (npm i -g @anthropic-ai/claude-code)");
|
|
42868
42680
|
if (!gw && !env.anthropicApiKey)
|
|
@@ -42880,10 +42692,6 @@ async function nativeRequirements(harness, env, onPath2) {
|
|
|
42880
42692
|
if (!gw && !env.openaiApiKey && !env.anthropicApiKey)
|
|
42881
42693
|
missing.push(`${access2}, ANTHROPIC_API_KEY or OPENAI_API_KEY`);
|
|
42882
42694
|
break;
|
|
42883
|
-
case "custom-http":
|
|
42884
|
-
if (!env.customHttpUrl)
|
|
42885
|
-
missing.push("EVAL_CUSTOM_HTTP_URL");
|
|
42886
|
-
break;
|
|
42887
42695
|
default:
|
|
42888
42696
|
missing.push(`a native runner (there is none for ${harness} yet; use --simulated)`);
|
|
42889
42697
|
}
|
|
@@ -42930,10 +42738,10 @@ async function loadSuites(candidate, candFiles, shared) {
|
|
|
42930
42738
|
}
|
|
42931
42739
|
return out;
|
|
42932
42740
|
}
|
|
42933
|
-
function parseSuite(bytes, ref,
|
|
42741
|
+
function parseSuite(bytes, ref, path18, source) {
|
|
42934
42742
|
const text = bytes.toString("utf8");
|
|
42935
42743
|
try {
|
|
42936
|
-
return { suite: parseEvalSuite(text,
|
|
42744
|
+
return { suite: parseEvalSuite(text, path18), ref, path: path18, source, hash: sha256(text) };
|
|
42937
42745
|
} catch (err) {
|
|
42938
42746
|
throw new SuiteError(err.message);
|
|
42939
42747
|
}
|
|
@@ -42950,7 +42758,7 @@ function narrowSuites(suites, f) {
|
|
|
42950
42758
|
}
|
|
42951
42759
|
|
|
42952
42760
|
// ../../packages/evals/dist/runners/shared.js
|
|
42953
|
-
import { spawn } from "child_process";
|
|
42761
|
+
import { spawn as spawn2 } from "child_process";
|
|
42954
42762
|
import { access, readFile as readFile6 } from "fs/promises";
|
|
42955
42763
|
import { constants } from "fs";
|
|
42956
42764
|
import path8 from "path";
|
|
@@ -43068,7 +42876,7 @@ async function onPath(bin, pathVar = process.env.PATH ?? "") {
|
|
|
43068
42876
|
function runProcess(cmd, args, opts) {
|
|
43069
42877
|
return new Promise((resolve, reject) => {
|
|
43070
42878
|
const started = Date.now();
|
|
43071
|
-
const child =
|
|
42879
|
+
const child = spawn2(cmd, args, { cwd: opts.cwd, env: opts.env, stdio: ["pipe", "pipe", "pipe"] });
|
|
43072
42880
|
let stdout = "";
|
|
43073
42881
|
let stderr = "";
|
|
43074
42882
|
let timedOut = false;
|
|
@@ -43291,10 +43099,10 @@ function redact(value, secrets) {
|
|
|
43291
43099
|
|
|
43292
43100
|
// ../../packages/evals/dist/cache.js
|
|
43293
43101
|
import { mkdir as mkdir5, readFile as readFile7, rename, writeFile as writeFile5 } from "fs/promises";
|
|
43294
|
-
import
|
|
43102
|
+
import os7 from "os";
|
|
43295
43103
|
import path9 from "path";
|
|
43296
43104
|
function defaultCacheDir(env = process.env) {
|
|
43297
|
-
return env.YARKR_CACHE_DIR || path9.join(env.XDG_CACHE_HOME || path9.join(
|
|
43105
|
+
return env.YARKR_CACHE_DIR || path9.join(env.XDG_CACHE_HOME || path9.join(os7.homedir(), ".cache"), "yarkr");
|
|
43298
43106
|
}
|
|
43299
43107
|
function fileTrialCache(dir) {
|
|
43300
43108
|
const root = path9.join(dir, "evals");
|
|
@@ -43324,7 +43132,7 @@ function fileTrialCache(dir) {
|
|
|
43324
43132
|
// ../../packages/evals/dist/execute.js
|
|
43325
43133
|
import { randomUUID } from "crypto";
|
|
43326
43134
|
import { mkdir as mkdir6, rm as rm2, stat as stat2 } from "fs/promises";
|
|
43327
|
-
import
|
|
43135
|
+
import os8 from "os";
|
|
43328
43136
|
import path11 from "path";
|
|
43329
43137
|
|
|
43330
43138
|
// ../../packages/evals/dist/graders/index.js
|
|
@@ -43561,11 +43369,12 @@ async function gradeReal(ctx) {
|
|
|
43561
43369
|
}
|
|
43562
43370
|
|
|
43563
43371
|
// ../../packages/evals/dist/runners/claude-code.js
|
|
43564
|
-
function claudeCodeAdapter(env
|
|
43372
|
+
function claudeCodeAdapter(env) {
|
|
43373
|
+
const fidelity = "native";
|
|
43565
43374
|
const pathVar = baseProcessEnv(env).PATH;
|
|
43566
43375
|
let cachedVersion = null;
|
|
43567
43376
|
return {
|
|
43568
|
-
id:
|
|
43377
|
+
id: "claude-code",
|
|
43569
43378
|
fidelity,
|
|
43570
43379
|
async available() {
|
|
43571
43380
|
return await onPath("claude", pathVar) !== null;
|
|
@@ -43769,67 +43578,6 @@ function codexAdapter(env) {
|
|
|
43769
43578
|
};
|
|
43770
43579
|
}
|
|
43771
43580
|
|
|
43772
|
-
// ../../packages/evals/dist/runners/custom-http.js
|
|
43773
|
-
function customHttpAdapter(env) {
|
|
43774
|
-
const url2 = env.customHttpUrl;
|
|
43775
|
-
let files = {};
|
|
43776
|
-
return {
|
|
43777
|
-
id: "custom-http",
|
|
43778
|
-
fidelity: "native",
|
|
43779
|
-
async available() {
|
|
43780
|
-
return !!url2;
|
|
43781
|
-
},
|
|
43782
|
-
async version() {
|
|
43783
|
-
return env.customHttpVersion ?? "custom";
|
|
43784
|
-
},
|
|
43785
|
-
async install(_pkg, f) {
|
|
43786
|
-
files = Object.fromEntries([...f].map(([k, v]) => [k, v.toString("base64")]));
|
|
43787
|
-
},
|
|
43788
|
-
async run(input2) {
|
|
43789
|
-
if (!url2)
|
|
43790
|
-
throw new Error("EVAL_CUSTOM_HTTP_URL is not set.");
|
|
43791
|
-
const started = Date.now();
|
|
43792
|
-
const res = await fetch(url2, {
|
|
43793
|
-
method: "POST",
|
|
43794
|
-
signal: AbortSignal.timeout(input2.limits.timeoutMs),
|
|
43795
|
-
headers: {
|
|
43796
|
-
"content-type": "application/json",
|
|
43797
|
-
...env.customHttpToken ? { authorization: `Bearer ${env.customHttpToken}` } : {}
|
|
43798
|
-
},
|
|
43799
|
-
body: JSON.stringify({
|
|
43800
|
-
case: { id: input2.evalCase.id, prompt: input2.evalCase.prompt },
|
|
43801
|
-
model: input2.model,
|
|
43802
|
-
limits: input2.limits,
|
|
43803
|
-
package: { name: input2.pkg.name, version: input2.pkg.label, files, encoding: "base64" }
|
|
43804
|
-
})
|
|
43805
|
-
});
|
|
43806
|
-
if (!res.ok)
|
|
43807
|
-
throw new Error(`custom-http runner returned ${res.status}: ${(await res.text()).slice(0, 300)}`);
|
|
43808
|
-
const t = await res.json();
|
|
43809
|
-
if (typeof t.output !== "string")
|
|
43810
|
-
throw new Error("custom-http runner response is missing `output`.");
|
|
43811
|
-
return {
|
|
43812
|
-
transcript: {
|
|
43813
|
-
harness: input2.harness,
|
|
43814
|
-
harness_version: t.harness_version ?? await this.version(),
|
|
43815
|
-
model: input2.model,
|
|
43816
|
-
events: t.events ?? [{ role: "assistant", content: t.output, at_ms: 0 }],
|
|
43817
|
-
output: t.output,
|
|
43818
|
-
files: t.files ?? {},
|
|
43819
|
-
tool_calls: t.tool_calls ?? [],
|
|
43820
|
-
skills_loaded: t.skills_loaded ?? [],
|
|
43821
|
-
turns: t.turns ?? 1,
|
|
43822
|
-
tokens_in: t.tokens_in ?? 0,
|
|
43823
|
-
tokens_out: t.tokens_out ?? 0,
|
|
43824
|
-
cost_usd: t.cost_usd ?? 0,
|
|
43825
|
-
latency_ms: t.latency_ms ?? Date.now() - started,
|
|
43826
|
-
fidelity: "native"
|
|
43827
|
-
}
|
|
43828
|
-
};
|
|
43829
|
-
}
|
|
43830
|
-
};
|
|
43831
|
-
}
|
|
43832
|
-
|
|
43833
43581
|
// ../../packages/evals/dist/runners/opencode.js
|
|
43834
43582
|
function opencodeAdapter(env) {
|
|
43835
43583
|
const pathVar = baseProcessEnv(env).PATH;
|
|
@@ -44027,11 +43775,9 @@ function synthesize(input2, c, plan) {
|
|
|
44027
43775
|
|
|
44028
43776
|
// ../../packages/evals/dist/runners/index.js
|
|
44029
43777
|
var NATIVE = {
|
|
44030
|
-
"claude-code":
|
|
44031
|
-
"claude-cowork": (env) => claudeCodeAdapter(env, "equivalent"),
|
|
43778
|
+
"claude-code": claudeCodeAdapter,
|
|
44032
43779
|
codex: codexAdapter,
|
|
44033
|
-
opencode: opencodeAdapter
|
|
44034
|
-
"custom-http": customHttpAdapter
|
|
43780
|
+
opencode: opencodeAdapter
|
|
44035
43781
|
};
|
|
44036
43782
|
var NativeUnavailableError = class extends Error {
|
|
44037
43783
|
};
|
|
@@ -44080,7 +43826,7 @@ async function executeRun(input2) {
|
|
|
44080
43826
|
const { candidate, baseline, env } = input2;
|
|
44081
43827
|
const suites = input2.harnesses?.length || input2.models?.length ? narrowSuites(input2.suites, { harnesses: input2.harnesses, models: input2.models }) : input2.suites;
|
|
44082
43828
|
const shards = planShards(suites, input2.mode, !!baseline);
|
|
44083
|
-
const tmpRoot = input2.tmpRoot ?? path11.join(
|
|
43829
|
+
const tmpRoot = input2.tmpRoot ?? path11.join(os8.tmpdir(), "yarkr-eval", runId);
|
|
44084
43830
|
const timeoutMs = input2.shardTimeoutMs ?? DEFAULT_SHARD_TIMEOUT_MS;
|
|
44085
43831
|
const secrets = secretsOf(env);
|
|
44086
43832
|
const adapterFor = adapterPicker(env, { native: input2.native, strict: input2.strict });
|
|
@@ -44227,7 +43973,8 @@ async function executeRun(input2) {
|
|
|
44227
43973
|
const draft = buildReport({
|
|
44228
43974
|
runId,
|
|
44229
43975
|
mode: input2.mode,
|
|
44230
|
-
|
|
43976
|
+
// Placeholder: the status depends on the report, and is set just below.
|
|
43977
|
+
status: "failed",
|
|
44231
43978
|
baselineVersion: baseline?.label ?? null,
|
|
44232
43979
|
candidateVersion: input2.candidateVersion ?? null,
|
|
44233
43980
|
suites,
|
|
@@ -44406,7 +44153,7 @@ ${suites.join("\n")}
|
|
|
44406
44153
|
import { execFile } from "child_process";
|
|
44407
44154
|
import { existsSync as existsSync5, readFileSync as readFileSync2 } from "fs";
|
|
44408
44155
|
import { mkdtemp, rm as rm3 } from "fs/promises";
|
|
44409
|
-
import
|
|
44156
|
+
import os9 from "os";
|
|
44410
44157
|
import path12 from "path";
|
|
44411
44158
|
import { promisify } from "util";
|
|
44412
44159
|
var exec = promisify(execFile);
|
|
@@ -44465,7 +44212,7 @@ async function checkoutRef(dir, ref) {
|
|
|
44465
44212
|
if (!commit) {
|
|
44466
44213
|
throw new CliError(`git ref "${ref}" doesn't exist here.`, "In CI, check out with `fetch-depth: 0` or fetch the base branch first, e.g. `git fetch origin main`.", 2);
|
|
44467
44214
|
}
|
|
44468
|
-
const tmp = await mkdtemp(path12.join(
|
|
44215
|
+
const tmp = await mkdtemp(path12.join(os9.tmpdir(), "yarkr-baseline-"));
|
|
44469
44216
|
const wt = path12.join(tmp, "tree");
|
|
44470
44217
|
try {
|
|
44471
44218
|
await exec("git", ["worktree", "add", "--detach", "--force", wt, commit], { cwd: top });
|
|
@@ -44489,21 +44236,21 @@ async function checkoutRef(dir, ref) {
|
|
|
44489
44236
|
}
|
|
44490
44237
|
|
|
44491
44238
|
// src/eval/registry.ts
|
|
44492
|
-
async function registrySnapshot(
|
|
44493
|
-
const pkg = await
|
|
44239
|
+
async function registrySnapshot(api, name, opts = {}) {
|
|
44240
|
+
const pkg = await api.pkgOrNull(name);
|
|
44494
44241
|
if (!pkg) return null;
|
|
44495
|
-
const rel2 = await
|
|
44496
|
-
const bundle = await
|
|
44242
|
+
const rel2 = await api.resolve(name, { channel: opts.channel ?? "stable", range: opts.range });
|
|
44243
|
+
const bundle = await api.bundle(name, rel2.version);
|
|
44497
44244
|
const files = new Map(bundle.files.map((f) => [f.path, Buffer.from(f.content, "base64")]));
|
|
44498
|
-
const tree = buildTree([...files].map(([
|
|
44245
|
+
const tree = buildTree([...files].map(([path18, bytes]) => ({ path: path18, bytes })));
|
|
44499
44246
|
return { snapshot: { name, label: bundle.version, contentHash: bundle.content_hash, manifest: bundle.manifest, tree }, files };
|
|
44500
44247
|
}
|
|
44501
44248
|
function registrySuiteResolver(getApi) {
|
|
44502
44249
|
return {
|
|
44503
44250
|
async resolve(name, range) {
|
|
44504
|
-
const
|
|
44505
|
-
if (!
|
|
44506
|
-
return registrySnapshot(
|
|
44251
|
+
const api = await getApi();
|
|
44252
|
+
if (!api) throw new SuiteError(`Shared suite ${name}@${range} needs a registry. Set YARKR_REGISTRY (and YARKR_TOKEN), or run \`yarkr login\`.`);
|
|
44253
|
+
return registrySnapshot(api, name, { range: range === "*" ? void 0 : range });
|
|
44507
44254
|
}
|
|
44508
44255
|
};
|
|
44509
44256
|
}
|
|
@@ -44574,7 +44321,7 @@ function matchPackage(scan, pkg) {
|
|
|
44574
44321
|
}
|
|
44575
44322
|
|
|
44576
44323
|
// src/eval/upload.ts
|
|
44577
|
-
import
|
|
44324
|
+
import os10 from "os";
|
|
44578
44325
|
function toImportedTrial(t, transcripts) {
|
|
44579
44326
|
const { events: _events, tool_calls: _calls, files: _files, output: _output, ...summary } = t.transcript;
|
|
44580
44327
|
return {
|
|
@@ -44596,7 +44343,7 @@ function runnerLabel(env = process.env) {
|
|
|
44596
44343
|
const url2 = env.GITHUB_SERVER_URL && env.GITHUB_REPOSITORY && env.GITHUB_RUN_ID ? ` ${env.GITHUB_SERVER_URL}/${env.GITHUB_REPOSITORY}/actions/runs/${env.GITHUB_RUN_ID}` : "";
|
|
44597
44344
|
return `github-actions${url2}`.slice(0, 200);
|
|
44598
44345
|
}
|
|
44599
|
-
return `yarkr-cli on ${env.CI ? "ci" :
|
|
44346
|
+
return `yarkr-cli on ${env.CI ? "ci" : os10.platform()}`;
|
|
44600
44347
|
}
|
|
44601
44348
|
async function githubOidcToken(env = process.env, fetchImpl = fetch) {
|
|
44602
44349
|
const url2 = env.ACTIONS_ID_TOKEN_REQUEST_URL;
|
|
@@ -44830,15 +44577,15 @@ async function resolveBaseline(dir, pkg, opts, getApi, say) {
|
|
|
44830
44577
|
}
|
|
44831
44578
|
}
|
|
44832
44579
|
if (spec === "registry" || spec === "auto") {
|
|
44833
|
-
const
|
|
44834
|
-
if (!
|
|
44580
|
+
const api = await getApi();
|
|
44581
|
+
if (!api || spec === "auto" && !pkg.named) {
|
|
44835
44582
|
if (spec === "registry") throw fail("--baseline registry needs a registry.", "Set YARKR_REGISTRY and YARKR_TOKEN, or run `yarkr login`.");
|
|
44836
44583
|
if (say) ui.step("No baseline: no registry configured or no package name. Use --baseline git:<ref> or <dir> to compare.");
|
|
44837
44584
|
return noBaseline();
|
|
44838
44585
|
}
|
|
44839
44586
|
let rel2;
|
|
44840
44587
|
try {
|
|
44841
|
-
rel2 = await registrySnapshot(
|
|
44588
|
+
rel2 = await registrySnapshot(api, pkg.snapshot.name);
|
|
44842
44589
|
} catch (err) {
|
|
44843
44590
|
if (spec === "registry") throw fail(`Couldn't fetch the registry baseline for ${pkg.snapshot.name}: ${err.message}`);
|
|
44844
44591
|
if (say) ui.step(`No baseline: ${err.message}`);
|
|
@@ -44859,8 +44606,8 @@ async function resolveBaseline(dir, pkg, opts, getApi, say) {
|
|
|
44859
44606
|
} };
|
|
44860
44607
|
}
|
|
44861
44608
|
async function upload(dir, pkg, run3, mode, getApi, env, say) {
|
|
44862
|
-
const
|
|
44863
|
-
if (!
|
|
44609
|
+
const api = await getApi();
|
|
44610
|
+
if (!api) throw fail("--report needs a registry and a token.", "Set YARKR_REGISTRY and YARKR_TOKEN, or run `yarkr login`.");
|
|
44864
44611
|
if (run3.trials.length > 5e3) throw fail(`${run3.package}: ${run3.trials.length} trials are more than one upload takes (5000). Narrow the run with --suite, --harness or --model.`);
|
|
44865
44612
|
const git2 = pkg.named ? null : await gitInfo(dir);
|
|
44866
44613
|
if (!pkg.named && !git2) throw fail(`--report can't tell which package ${pkg.asset.name} is.`, "Pass --package <namespace/name>, or run inside a git checkout with an origin remote.");
|
|
@@ -44877,7 +44624,7 @@ async function upload(dir, pkg, run3, mode, getApi, env, say) {
|
|
|
44877
44624
|
}),
|
|
44878
44625
|
secretsOf(env)
|
|
44879
44626
|
);
|
|
44880
|
-
const res = await
|
|
44627
|
+
const res = await api.importEvalRun(body).catch((err) => {
|
|
44881
44628
|
throw fail(`Upload failed: ${err.message}`, err instanceof CliError ? err.hint : void 0);
|
|
44882
44629
|
});
|
|
44883
44630
|
if (say) ui.ok(`Uploaded (${res.trust}): ${res.url}`);
|
|
@@ -45059,8 +44806,240 @@ async function gradeCase(c, caseDir, pkgRoot, runScripts) {
|
|
|
45059
44806
|
}
|
|
45060
44807
|
}
|
|
45061
44808
|
|
|
44809
|
+
// src/commands/guide.ts
|
|
44810
|
+
import { mkdir as mkdir8, stat as stat3, writeFile as writeFile7 } from "fs/promises";
|
|
44811
|
+
import path16 from "path";
|
|
44812
|
+
|
|
44813
|
+
// ../../packages/core/dist/guides/content.generated.js
|
|
44814
|
+
var GUIDE_CONTENT = {
|
|
44815
|
+
"create-ark": '---\nname: create-ark\ndescription: Build a Yarkr ark (a set of skills, agents or MCP configs handed to a team) for a given topic and type. Use when asked to create, assemble or curate an ark, or to collect a topic\'s skills, agents or MCP servers for a team in Yarkr.\n---\n\n# Creating an ark from a topic and a type\n\nYou get two inputs and build one [ark](https://github.com/posterus-ltd/yarkr-public/blob/main/docs/arks.md) that hands out packages on that topic.\n\n| Input | Example | Meaning |\n| --- | --- | --- |\n| **topic** | `invoice processing`, `frontend testing` | what the ark is about |\n| **type** | `skill`, `agent` or `mcp` | the kind of package it holds. `mcp` is a **toolset** in Yarkr (`--kind toolset`, `kind: toolset`) |\n\nPlus, from the user or their config: the **org** (its slug is its GitHub login, lowercased), and whether the ark should\nbe **public**. Ask for the org if you can\'t tell; default to private.\n\nAn ark only points at packages. Packages come from GitHub ([github.md](https://github.com/posterus-ltd/yarkr-public/blob/main/docs/github.md)): there is no way to upload content to\nYarkr directly. So the work is: find what exists, write what\'s missing in a repo, then assemble the ark.\n\n```\n1. plan \u2500\u2500\u25B6 2. find existing \u2500\u2500\u25B6 3. author missing (PR) \u2500\u2500\u25B6 4. wait for index \u2500\u2500\u25B6 5. create ark + items \u2500\u2500\u25B6 6. verify\n```\n\n---\n\n## 1. Plan\n\n- **Ark name:** a slug, `^[a-z0-9][a-z0-9-]*$`, short and named after the topic: `invoice-processing`, not\n `ark-for-invoices`. It must be unique in the org.\n- **Description:** one sentence, at most 500 characters, saying who it\'s for and what they get.\n- **Scope:** aim for 3 to 8 packages. Every skill in an ark goes into every member\'s context; too many makes agents\n worse. Split a broad topic into several arks rather than one big one.\n- List the packages you expect to need, each with a one-line purpose, before searching.\n\n## 2. Find what already exists\n\nReuse beats writing. Search the registry for each planned package:\n\n```bash\nyarkr search "<topic words>" --kind <skill|agent|toolset> --json\nyarkr info <namespace>/<name> # source repo, targets, releases, eval results\n```\n\nOver MCP, `search_packages` with `scope: "all"`, then `get_skill` / `get_agent` / `get_toolset` to read one.\n\nKeep a package when:\n\n- its description and body actually cover the planned purpose (read it, don\'t trust the name);\n- the org can put it in an ark: **the org\'s own namespace, or any public package**;\n- for a public ark: **it is public**. A public ark can hold nothing else;\n- it isn\'t yanked or archived, and has evals that pass if any are shown.\n\n## 3. Author what\'s missing\n\nWrite each missing package in one of the org\'s **connected** repos (check **Settings \u2192 GitHub** / `/orgs/<org>/github`;\na repo that isn\'t connected is never indexed). For a public ark the repo must be public. Open **one pull request** with\nall new packages, and describe the ark they\'re for. Merging is publishing; don\'t push to the default branch yourself\nunless the user tells you to.\n\nPackage names come from the folder or `name:` frontmatter, slugified, and publish as `<org>/<name>`. Check that the name\ndoesn\'t already exist in the org.\n\n### Type `skill`\n\nA folder with `SKILL.md`. Everything in the folder ships with it. This guide is itself one.\n\n```\nskills/<name>/\n SKILL.md\n references/\u2026 # optional: long docs the skill loads on demand\n scripts/\u2026 # optional\n evals/core.yaml # optional but recommended, see https://github.com/posterus-ltd/yarkr-public/blob/main/docs/evals.md\n```\n\n```markdown\n---\nname: <name>\ndescription: <what it does and when to use it. Harnesses decide whether to load the skill from this line alone, so name the trigger situations.>\n---\n\n# <Title>\n\n<Steps the agent follows. Concrete and imperative. Point to references/ for anything long.>\n```\n\n`description` is required; without it the skill isn\'t indexed.\n\n### Type `agent`\n\nOne markdown file under `agents/` (or `.claude/agents/`).\n\n```markdown\n---\nname: <name>\ndescription: <when to hand work to this agent>\nmodel: <optional>\ntools: Read, Grep, Bash # optional\nskills: <skill-name>, other-org/skill # optional: dependencies, installed with the agent\n---\n\n<System prompt: role, what it does, how it decides, what it returns.>\n```\n\n- `description` is required; a file without it is treated as a plain doc.\n- A bare name in `skills:` means a skill in the same org. Use `ns/name` for another namespace. A skill the agent needs\n that doesn\'t exist yet is part of this same PR.\n- Add the agent\'s skills to the ark too, or leave them to the dependency: `yarkr sync` installs dependencies either way.\n\n### Type `mcp` (toolset)\n\nOne toolset per folder, in Claude Code\'s `.mcp.json` format:\n\n```\ntoolsets/<name>/\n .mcp.json\n README.md # first paragraph becomes the description\n```\n\n```json\n{\n "mcpServers": {\n "<server>": {\n "type": "http",\n "url": "https://mcp.example.com/mcp",\n "headers": { "Authorization": "Bearer ${EXAMPLE_TOKEN}" }\n }\n }\n}\n```\n\n- **No literal secrets.** Values in `env` and `headers` must be `${VAR}` (becomes `${env:VAR}`), `${VAR:-default}`\n or `${vault:path#key}`. A literal value is refused.\n- Prefer servers you can verify exist: the vendor\'s official server, or a well-known package for `stdio` (`npx -y \u2026`).\n Never invent a URL or package name. If you can\'t confirm one, stop and ask.\n- Document in the README which variables each user must set.\n\n### Optional `yarkr.yaml`\n\nNext to any asset, for what can\'t be inferred:\n\n```yaml\ntargets: [claude-code, codex] # default: every harness\ntags: [<topic>, \u2026] # helps search; use the topic\nevals: [evals/core.yaml]\n```\n\n## 4. Wait for the index\n\nAfter the PR merges, the push is indexed in the background, usually within a minute. Each package\'s first release is a\nsnapshot of the default branch (`0.0.0-main.\u2026`) unless a tag says otherwise.\n\n```bash\nyarkr info <org>/<name> # repeat until it shows a stable version\n```\n\nIf it never appears, check the repo\'s row on the org\'s GitHub page: detection problems (missing description, literal\nsecret, name clash) are listed there. Fix them in a new PR.\n\n## 5. Create the ark and add items\n\nArk changes need an **org admin** and a **read and write** token. There\'s no CLI command for this; use the web app\n(**Arks \u2192 your org**) or the API. The base URL is the registry (`yarkr whoami` prints it; the hub is\n`https://api.yarkr.com/functions/v1/api`).\n\n```bash\nAPI=https://api.yarkr.com/functions/v1/api/api/v1\nAUTH="Authorization: Bearer $YARKR_TOKEN"\n\n# Create\ncurl -sf -X POST "$API/arks/<org>" -H "$AUTH" -H \'content-type: application/json\' \\\n -d \'{"name":"<ark>","description":"<one sentence>"}\'\n\n# One call per package\ncurl -sf -X PUT "$API/arks/<org>/<ark>/items/<ns>/<name>" -H "$AUTH" -H \'content-type: application/json\' \\\n -d \'{"range":"^1","required":true}\'\n```\n\nItem body:\n\n| Field | Use |\n| --- | --- |\n| `range` | Semver range. Use `^<major>` for tagged packages. Omit it (and `channel`) to follow `stable`, which suits new snapshot-only packages |\n| `channel` | Instead of a range, e.g. `stable` |\n| `required` | `true` for the core of the topic; `false` for extras members may exclude |\n| `config` | Toolsets only: per-ark overrides, `{"servers": {"<server>": {"env": {\u2026}, "headers": {\u2026}, "args": [\u2026], "url": "\u2026"}}}`. Secret values must be `${env:\u2026}` or `${vault:\u2026}` |\n\nThe server rejects an item that the org can\'t use, a private package in a public ark, a bad range, a literal secret,\nor a range that conflicts with another ark sharing a member. Read the error and fix the cause; don\'t retry blindly.\n\nThen, only if asked:\n\n```bash\n# Make it public (public packages only)\ncurl -sf -X PATCH "$API/arks/<org>/<ark>" -H "$AUTH" -H \'content-type: application/json\' -d \'{"public":true}\'\n\n# Add members (they must already belong to the org)\ncurl -sf -X POST "$API/arks/<org>/<ark>/members" -H "$AUTH" -H \'content-type: application/json\' -d \'{"email":"\u2026"}\'\n```\n\n## 6. Verify\n\n```bash\ncurl -sf "$API/arks/<org>/<ark>" -H "$AUTH" # items, ranges, description\nyarkr ark lint <org>/<ark> --strict # fix every error and warning it reports\nyarkr sync <org>/<ark> --dry-run --harness claude-code # resolves every item without writing files\n```\n\nFor a public ark, also check `yarkr arks` lists it.\n\n## Report back\n\nTell the user:\n\n- the ark (`<org>/<ark>`), its description and whether it\'s public;\n- each item: reused or new, range, required or optional, one line on why it\'s there;\n- the PR link for new packages, and whether it\'s merged;\n- what\'s left for them: merging the PR, adding members, setting the toolset variables listed in the READMEs, and how\n people get it (`yarkr sync <org>/<ark>`, or `yarkr mcp add <org>/<ark>`).\n\n## Don\'ts\n\n- Don\'t put literal secrets anywhere: repo, ark config or PR description.\n- Don\'t add packages you haven\'t read.\n- Don\'t make an ark public, add members, or merge a PR unless the user asked.\n- Don\'t pad the ark to reach a number. Three good packages beat eight vague ones.\n',
|
|
44816
|
+
"index-repo": "---\nname: index-repo\ndescription: Make an existing repo a Yarkr source by adding one yarkr.index.yaml that points at the skills, agents and MCP configs already in it, in whatever layout they have, without moving or rewriting files. Use when asked to publish a repo's skills to Yarkr, make a repo Yarkr-compatible or conforming, or when lint or the hub doesn't find skills that are in the repo.\n---\n\n# Making a repo a Yarkr source\n\nYarkr publishes skills, agents and MCP configs (toolsets) from GitHub repos\n([github.md](https://github.com/posterus-ltd/yarkr-public/blob/main/docs/github.md)). It already finds assets in their\nusual layouts. Skills kept any other way (a single markdown file, a folder with a README instead of `SKILL.md`, no\nfrontmatter) are listed in one file at the repo root, `yarkr.index.yaml`, which says where each one lives and adds the\nname and description the file itself lacks. Agents and MCP configs work the same way.\n\n**The goal is the smallest possible diff:** ideally one new file. Don't move, rename or reformat existing files, and\ndon't add frontmatter to them: the index carries it. The only edits to existing files you may need are removing literal\nsecrets from MCP configs (step 5).\n\n```\n1. lint \u2500\u2500\u25B6 2. survey \u2500\u2500\u25B6 3. choose \u2500\u2500\u25B6 4. write yarkr.index.yaml \u2500\u2500\u25B6 5. fix secrets \u2500\u2500\u25B6 6. lint clean \u2500\u2500\u25B6 7. PR\n```\n\n---\n\n## 1. See what Yarkr already finds\n\nFrom the repo root:\n\n```bash\nnpx yarkr-cli lint # or `yarkr lint`; --json for machine-readable output\n```\n\nIt lists every asset that would be published (name, kind, path, description), using the same detector as the hub,\nthen **errors** (what the hub would refuse) and **warnings** (unknown index keys, descriptions that don't say when to\nuse the asset, agent skills missing from the repo). These are found without an index:\n\n| Layout | Becomes |\n| --- | --- |\n| `<dir>/SKILL.md` with `description` frontmatter | a skill; the whole folder ships with it |\n| `agents/<name>.md`, `.claude/agents/<name>.md` with `description` frontmatter | an agent |\n| `.mcp.json` at the root, `toolsets/<name>/.mcp.json` | a toolset |\n\nAnything listed here needs no index entry. Fix what it reports in step 4 or 5.\n\n## 2. Find the skills Yarkr misses\n\nLook for skills, agents and MCP configs that step 1 didn't list. They're usually there, just in a different shape:\n\n| You find | It is | In the index |\n| --- | --- | --- |\n| A folder of instructions plus scripts or references, with `README.md` (or another `.md`) instead of `SKILL.md` | a skill | `path` to the folder, `entry` to its instructions file |\n| A single markdown file with a skill's instructions (`ai/skills/code-review.md`) | a skill | `path` to the file |\n| A `SKILL.md` without `description` frontmatter | a skill | `path` plus `description`, instead of editing the file |\n| Skills under a folder that Yarkr ignores, or nested inside another skill | skills | one entry each |\n| An agent definition outside `agents/` or `.claude/agents/`, or without `description` | an agent | `path`, `description`, and its `skills` |\n| An MCP config other than a root `.mcp.json` or `toolsets/<name>/.mcp.json` (`.cursor/mcp.json`, `.vscode/mcp.json`) | a toolset | `path` and `name` |\n\nSearch by content as well as by name: skills tend to have imperative steps for a task and a \"when to use\" line.\nIgnore `node_modules`, vendored code, test fixtures, generated files, and examples that show a format rather than\nbeing a skill.\n\n## 3. Choose what to publish\n\nPublish a skill only if **someone outside this repo would load it** for a recognisable task. For each one, decide:\n\n- **Kind.** Steps for a task are a **skill**. A role the main agent delegates to (with its own system prompt, tools,\n maybe model) is an **agent**. MCP server config is a **toolset**.\n- **Keep out:** `CLAUDE.md`, `AGENTS.md` and other files that only describe this codebase (its layout, commands,\n conventions). They're project context, not skills.\n- **Description.** One or two sentences: what it does, then *when to use it* (\"Use when \u2026\"). Harnesses decide whether\n to load a skill from this line alone, so name the trigger situations. Read the file; don't guess from its name.\n- **Name.** A short slug, unique in the repo, `<org>/<name>` once published. Defaults to the frontmatter `name`, else the\n file or folder name. Set `name` when the default is vague (`README`, `howto`).\n- **A file or a folder.** A lone markdown file is a skill on its own. If it relies on scripts, templates or references\n next to it, point at the folder instead, with `entry` naming the instructions file.\n\nIf unsure whether something belongs, ask the user with your shortlist rather than publishing everything.\n\n## 4. Write `yarkr.index.yaml`\n\nAt the repo root (or at the **root folder** set when the repo was connected). Paths are relative to the index file.\nList only what step 1 didn't already find.\n\n```yaml\n# Assets Yarkr publishes from this repo, in addition to the usual layouts.\n# https://github.com/posterus-ltd/yarkr-public/blob/main/docs/github.md#yarkrindexyaml\nskills:\n - path: ai/skills/code-review.md # one file: the whole skill\n description: Review a diff for bugs, security issues and missing tests. Use when asked to review a PR or a change.\n - path: ai/skills/pdf # a folder: everything in it ships\n entry: README.md # its instructions file (default SKILL.md, else README.md)\n name: pdf-forms\n description: Fill and read PDF forms with the bundled scripts. Use for any PDF form task.\n - ai/skills/release/howto.md # a bare path works when the file has description frontmatter\n\nagents:\n - path: ai/triage-agent.md\n description: Triages new GitHub issues into labels and owners. Hand it any untriaged issue.\n skills: [code-review] # skills it uses: a name here, or <org>/<name> elsewhere\n tools: [Read, Grep] # optional\n model: sonnet # optional\n\ntoolsets:\n - path: .cursor/mcp.json\n name: github\n description: GitHub's MCP server for issues and PRs. Needs GITHUB_TOKEN.\n```\n\nEvery entry takes `path` and, optionally, `name`, `description`, `tags`, `targets` (harness ids) and `evals` (suite\npaths). Values in the index win over the file's frontmatter.\n\nAdd `detect: false` at the top level when the repo has `SKILL.md` or `agents/*.md` files you don't want published\n(fixtures, examples, drafts): then only the index is published.\n\n## 5. Remove literal secrets from MCP configs\n\nA toolset with a literal value in `env` or `headers` is refused. Replace each with `${VAR}` (or `${vault:path#key}`)\nand tell the user which variables to set. This is the one case where you edit an existing file; mention it in the PR.\nIf the file is also used locally with real values, it's leaking a secret already: say so.\n\n## 6. Lint until clean\n\n```bash\nnpx yarkr-cli lint --strict\n```\n\nIt exits 1 on errors, and with `--strict` on warnings too. Fix warnings unless there's a reason not to (say, an agent's\nskill published from another repo). Check that every asset you chose appears once, with the name and description you\nmeant, and nothing you left out appears. Suggest adding `npx yarkr-cli lint` to CI so the index can't drift from the\nfiles it points at.\n\n## 7. Hand it over\n\n- Open a PR with `yarkr.index.yaml` (and any secret fixes). The description lists what will be published and why the\n rest was left out.\n- After merge, an org admin connects the repo in Yarkr (**the org's GitHub page \u2192 Connect**). Every push to the default\n branch publishes a new release of each asset whose files changed.\n- To change an asset later, edit its file where it is. Moving it means updating its `path` in the index.\n\n## Rules\n\n- Never invent an asset, a description that the file doesn't support, or an MCP server URL or package.\n- Never move, rename or rewrite existing files to fit Yarkr. The index exists so you don't have to.\n- One asset per entry; names unique. Don't list the same file twice or a file inside a listed folder.\n"
|
|
44817
|
+
};
|
|
44818
|
+
|
|
44819
|
+
// ../../packages/core/dist/guides/index.js
|
|
44820
|
+
var GUIDE_NAMES = Object.keys(GUIDE_CONTENT);
|
|
44821
|
+
var descriptionOf = (md2) => /^---\n[\s\S]*?^description:\s*(.+)$/m.exec(md2)?.[1]?.trim() ?? "";
|
|
44822
|
+
var isGuideName = (n) => Object.hasOwn(GUIDE_CONTENT, n);
|
|
44823
|
+
function getGuide(name) {
|
|
44824
|
+
const content = GUIDE_CONTENT[name];
|
|
44825
|
+
return { name, description: descriptionOf(content), content };
|
|
44826
|
+
}
|
|
44827
|
+
var ARK_TYPES = { skill: "skill", agent: "agent", mcp: "toolset" };
|
|
44828
|
+
function createArkPrompt(inputs = {}) {
|
|
44829
|
+
const body = GUIDE_CONTENT["create-ark"].replace(/^---\n[\s\S]*?\n---\n+/, "");
|
|
44830
|
+
const given = [
|
|
44831
|
+
inputs.topic && `- topic: ${inputs.topic}`,
|
|
44832
|
+
inputs.type && `- type: ${inputs.type} (package kind \`${ARK_TYPES[inputs.type]}\`)`,
|
|
44833
|
+
inputs.org && `- org: ${inputs.org}`
|
|
44834
|
+
].filter(Boolean);
|
|
44835
|
+
return given.length ? `${body.trimEnd()}
|
|
44836
|
+
|
|
44837
|
+
---
|
|
44838
|
+
|
|
44839
|
+
Your inputs:
|
|
44840
|
+
|
|
44841
|
+
${given.join("\n")}
|
|
44842
|
+
` : body;
|
|
44843
|
+
}
|
|
44844
|
+
|
|
44845
|
+
// src/commands/guide.ts
|
|
44846
|
+
async function guide(name, opts) {
|
|
44847
|
+
if (!name) {
|
|
44848
|
+
ui.table(GUIDE_NAMES.map((n) => [ui.bold(n), getGuide(n).description]), ["guide", "description"]);
|
|
44849
|
+
ui.step(`${ui.code("yarkr guide <name>")} prints one; ${ui.code("--out <dir>")} saves it as <dir>/SKILL.md.`);
|
|
44850
|
+
return;
|
|
44851
|
+
}
|
|
44852
|
+
if (!isGuideName(name)) throw new CliError(`No guide named ${name}.`, `Guides: ${GUIDE_NAMES.join(", ")}.`);
|
|
44853
|
+
const text = name === "create-ark" && (opts.topic || opts.type) ? createArkPrompt({ topic: opts.topic, type: opts.type }) : getGuide(name).content;
|
|
44854
|
+
if (!opts.out) return void process.stdout.write(text);
|
|
44855
|
+
const isDir = opts.out.endsWith("/") || opts.out.endsWith(path16.sep) || (await stat3(opts.out).catch(() => null))?.isDirectory();
|
|
44856
|
+
const file2 = path16.resolve(isDir ? path16.join(opts.out, "SKILL.md") : opts.out);
|
|
44857
|
+
await mkdir8(path16.dirname(file2), { recursive: true });
|
|
44858
|
+
await writeFile7(file2, text);
|
|
44859
|
+
ui.ok(`Wrote ${name} to ${file2}`);
|
|
44860
|
+
}
|
|
44861
|
+
|
|
44862
|
+
// src/commands/lint.ts
|
|
44863
|
+
var import_semver3 = __toESM(require_semver2(), 1);
|
|
44864
|
+
var MAX_ITEMS = 8;
|
|
44865
|
+
var EVAL_PASS = 0.8;
|
|
44866
|
+
var SECRETISH = /(token|secret|password|passwd|api[_-]?key|private[_-]?key|credential|auth)/i;
|
|
44867
|
+
var isTagged = (v) => !import_semver3.default.prerelease(v);
|
|
44868
|
+
async function lintArk(api, ref) {
|
|
44869
|
+
const ark = await api.ark(ref);
|
|
44870
|
+
const findings = [];
|
|
44871
|
+
const add2 = (severity, rule, message, pkg) => findings.push({ severity, rule, message, ...pkg ? { package: pkg } : {} });
|
|
44872
|
+
if (!ark.description.trim()) add2("warning", "description", "The ark has no description. Say in one sentence who it's for and what they get.");
|
|
44873
|
+
if (!ark.items.length) add2("error", "empty", "The ark has no items, so it gives its members nothing.");
|
|
44874
|
+
if (ark.items.length > MAX_ITEMS) add2("warning", "size", `The ark has ${ark.items.length} items. Past ${MAX_ITEMS}, agents get worse; split it into narrower arks.`);
|
|
44875
|
+
const details = /* @__PURE__ */ new Map();
|
|
44876
|
+
const detail = async (name) => {
|
|
44877
|
+
if (!details.has(name)) details.set(name, await api.pkgOrNull(name));
|
|
44878
|
+
return details.get(name);
|
|
44879
|
+
};
|
|
44880
|
+
const releases = await Promise.all(ark.items.map((item) => lintItem(api, ark, item, detail, add2)));
|
|
44881
|
+
if (ark.public) {
|
|
44882
|
+
for (const rel2 of releases) {
|
|
44883
|
+
if (!rel2) continue;
|
|
44884
|
+
const deps = Object.keys({ ...rel2.manifest.depends.skills, ...rel2.manifest.depends.toolsets, ...rel2.manifest.depends.agents });
|
|
44885
|
+
for (const dep of deps) {
|
|
44886
|
+
const d = await detail(dep);
|
|
44887
|
+
if (!d) add2("error", "dependency", `Depends on ${dep}, which doesn't exist or you can't read.`, rel2.package);
|
|
44888
|
+
else if (d.classification !== "public") add2("error", "public-dependency", `Depends on ${dep}, which isn't public, so people outside the org can't install it.`, rel2.package);
|
|
44889
|
+
}
|
|
44890
|
+
}
|
|
44891
|
+
}
|
|
44892
|
+
const order = { error: 0, warning: 1 };
|
|
44893
|
+
findings.sort((a, b) => order[a.severity] - order[b.severity] || (a.package ?? "").localeCompare(b.package ?? ""));
|
|
44894
|
+
return { ark, findings };
|
|
44895
|
+
}
|
|
44896
|
+
async function lintItem(api, ark, item, detail, add2) {
|
|
44897
|
+
const name = item.package;
|
|
44898
|
+
const p = await detail(name);
|
|
44899
|
+
if (!p) {
|
|
44900
|
+
add2("error", "missing", "The package doesn't exist, or you can't read it.", name);
|
|
44901
|
+
return null;
|
|
44902
|
+
}
|
|
44903
|
+
if (p.taken_down) {
|
|
44904
|
+
add2("error", "taken-down", `The package was taken down: ${p.taken_down.reason}`, name);
|
|
44905
|
+
return null;
|
|
44906
|
+
}
|
|
44907
|
+
if (ark.public && p.classification !== "public") add2("error", "public-item", `It's ${p.classification}, but a public ark may only hold public packages.`, name);
|
|
44908
|
+
if (!p.description.trim()) add2("warning", "item-description", "The package has no description, so members can't tell what it's for.", name);
|
|
44909
|
+
if (item.range && !import_semver3.default.validRange(item.range)) {
|
|
44910
|
+
add2("error", "range", `"${item.range}" isn't a semver range.`, name);
|
|
44911
|
+
return null;
|
|
44912
|
+
}
|
|
44913
|
+
let rel2 = null;
|
|
44914
|
+
try {
|
|
44915
|
+
rel2 = await api.resolve(name, { channel: item.channel ?? "stable", range: item.range ?? void 0 });
|
|
44916
|
+
} catch (err) {
|
|
44917
|
+
const what = item.range ? `range ${item.range}` : `channel ${item.channel ?? "stable"}`;
|
|
44918
|
+
add2("error", "unresolvable", `Nothing matches ${what}, so \`yarkr sync\` fails for every member (${err.message})`, name);
|
|
44919
|
+
}
|
|
44920
|
+
const live = p.releases.filter((r) => !r.yanked).map((r) => r.version);
|
|
44921
|
+
const newest = import_semver3.default.maxSatisfying(live.filter(isTagged), "*");
|
|
44922
|
+
if (!item.range && !item.channel && newest) add2("warning", "unpinned", `Follows stable although it has tagged releases. Pin a range like ^${import_semver3.default.major(newest)} so a new major doesn't reach members unreviewed.`, name);
|
|
44923
|
+
if (item.range && rel2 && newest && import_semver3.default.gt(newest, rel2.version) && !import_semver3.default.satisfies(newest, item.range)) {
|
|
44924
|
+
add2("warning", "outdated", `${newest} is out, but the range ${item.range} holds members at ${rel2.version}.`, name);
|
|
44925
|
+
}
|
|
44926
|
+
const ev = p.reported_eval;
|
|
44927
|
+
if (ev && (ev.status === "failed" || ev.pass_rate !== null && ev.pass_rate < EVAL_PASS)) {
|
|
44928
|
+
const rate = ev.pass_rate === null ? "" : ` (${Math.round(ev.pass_rate * 100)}% passed)`;
|
|
44929
|
+
add2("warning", "evals", `Its latest eval run on ${ev.version} failed${rate}.`, name);
|
|
44930
|
+
}
|
|
44931
|
+
const servers = item.config.servers ?? {};
|
|
44932
|
+
if (Object.keys(servers).length && item.kind !== "toolset") add2("error", "config", "Has server config, but only toolsets use it.", name);
|
|
44933
|
+
for (const [server, o] of Object.entries(servers)) {
|
|
44934
|
+
if (rel2?.manifest.toolset && !rel2.manifest.toolset.servers.some((s) => s.name === server)) {
|
|
44935
|
+
add2("warning", "config", `Configures server "${server}", which ${rel2.version} doesn't have (it has ${rel2.manifest.toolset.servers.map((s) => s.name).join(", ") || "none"}).`, name);
|
|
44936
|
+
}
|
|
44937
|
+
for (const field of ["env", "headers"]) {
|
|
44938
|
+
for (const [k, v] of Object.entries(o[field] ?? {})) {
|
|
44939
|
+
if (SECRETISH.test(k) && !SECRET_REF.test(v)) add2("error", "secret", `${server}.${field}.${k} holds a literal value. Use \${env:\u2026} or \${vault:path#key}.`, name);
|
|
44940
|
+
}
|
|
44941
|
+
}
|
|
44942
|
+
}
|
|
44943
|
+
return rel2;
|
|
44944
|
+
}
|
|
44945
|
+
async function arkLint(ref, opts) {
|
|
44946
|
+
const api = new Api(await resolveConnection({ dir: process.cwd() }));
|
|
44947
|
+
const { ark, findings } = await lintArk(api, ref);
|
|
44948
|
+
const errors = findings.filter((f) => f.severity === "error").length;
|
|
44949
|
+
const warnings = findings.length - errors;
|
|
44950
|
+
if (opts.json) console.log(JSON.stringify({ ark: ark.ref, errors, warnings, findings }, null, 2));
|
|
44951
|
+
else {
|
|
44952
|
+
ui.heading(`${ark.ref} ${ui.dim(`${ark.items.length} item(s)${ark.public ? ", public" : ""}`)}`);
|
|
44953
|
+
for (const f of findings) {
|
|
44954
|
+
const line = `${f.package ? `${ui.bold(f.package)} ` : ""}${f.message} ${ui.dim(`[${f.rule}]`)}`;
|
|
44955
|
+
if (f.severity === "error") ui.error(line);
|
|
44956
|
+
else ui.warn(line);
|
|
44957
|
+
}
|
|
44958
|
+
if (!findings.length) ui.ok("No problems found.");
|
|
44959
|
+
}
|
|
44960
|
+
if (errors || opts.strict && warnings) {
|
|
44961
|
+
throw new CliError(`${errors} error(s), ${warnings} warning(s) in ${ark.ref}.`, errors ? void 0 : "Warnings fail the lint because of --strict.");
|
|
44962
|
+
}
|
|
44963
|
+
if (warnings && !opts.json) ui.info(`${warnings} warning(s). Pass --strict to fail on them.`);
|
|
44964
|
+
return findings;
|
|
44965
|
+
}
|
|
44966
|
+
|
|
44967
|
+
// src/commands/repo-lint.ts
|
|
44968
|
+
var import_yaml5 = __toESM(require_dist(), 1);
|
|
44969
|
+
import { readFile as readFile10 } from "fs/promises";
|
|
44970
|
+
import path17 from "path";
|
|
44971
|
+
var INDEX_KEYS = /* @__PURE__ */ new Set(["skills", "agents", "toolsets", "detect"]);
|
|
44972
|
+
var ENTRY_KEYS = {
|
|
44973
|
+
skills: /* @__PURE__ */ new Set(["path", "name", "description", "tags", "targets", "evals", "entry"]),
|
|
44974
|
+
agents: /* @__PURE__ */ new Set(["path", "name", "description", "tags", "targets", "evals", "skills", "tools", "model"]),
|
|
44975
|
+
toolsets: /* @__PURE__ */ new Set(["path", "name", "description", "tags", "targets", "evals"])
|
|
44976
|
+
};
|
|
44977
|
+
var TRIGGER = /\b(use (it )?(when|for|to|if)|when (the user|asked|you)|whenever|hand it|for any)\b/i;
|
|
44978
|
+
var MIN_DESCRIPTION = 40;
|
|
44979
|
+
async function lintRepo(dir, opts = {}) {
|
|
44980
|
+
const res = await scanFolder(dir, { namespace: opts.namespace, fallbackNamespace: await gitOwner(dir) ?? void 0, label: "working tree" });
|
|
44981
|
+
const findings = [];
|
|
44982
|
+
const add2 = (severity, rule, message, pkg) => findings.push({ severity, rule, message, ...pkg ? { package: pkg } : {} });
|
|
44983
|
+
for (const p of res.problems) add2("error", "detect", `${p.path}: ${p.message}`);
|
|
44984
|
+
const indexText = await readFile10(path17.join(res.root, INDEX_FILE), "utf8").catch(() => null);
|
|
44985
|
+
if (indexText !== null) {
|
|
44986
|
+
let raw = null;
|
|
44987
|
+
try {
|
|
44988
|
+
raw = import_yaml5.default.parse(indexText);
|
|
44989
|
+
} catch {
|
|
44990
|
+
}
|
|
44991
|
+
if (raw && typeof raw === "object") {
|
|
44992
|
+
for (const [key, list] of Object.entries(raw)) {
|
|
44993
|
+
if (!INDEX_KEYS.has(key)) add2("warning", "index-key", `${INDEX_FILE}: unknown key \`${key}\` is ignored. Expected ${[...INDEX_KEYS].join(", ")}.`);
|
|
44994
|
+
if (!ENTRY_KEYS[key] || !Array.isArray(list)) continue;
|
|
44995
|
+
list.forEach((e, i) => {
|
|
44996
|
+
if (!e || typeof e !== "object") return;
|
|
44997
|
+
for (const k of Object.keys(e)) if (!ENTRY_KEYS[key].has(k)) add2("warning", "index-key", `${INDEX_FILE}: ${key}[${i}] has unknown key \`${k}\`, which is ignored.`);
|
|
44998
|
+
const targets = e.targets;
|
|
44999
|
+
for (const t of Array.isArray(targets) ? targets : []) {
|
|
45000
|
+
if (!HARNESS_IDS.includes(String(t))) add2("warning", "target", `${INDEX_FILE}: ${key}[${i}] targets unknown harness \`${t}\`. Known: ${HARNESS_IDS.join(", ")}.`);
|
|
45001
|
+
}
|
|
45002
|
+
});
|
|
45003
|
+
}
|
|
45004
|
+
}
|
|
45005
|
+
}
|
|
45006
|
+
const assets = res.packages.map(({ asset }) => ({ name: asset.manifest.name, kind: asset.kind, path: asset.path, description: asset.manifest.description, manifest: asset.manifest }));
|
|
45007
|
+
if (!assets.length && !res.problems.length) add2("error", "empty", `Nothing to publish. List assets in ${INDEX_FILE}; \`yarkr guide index-repo\` explains how.`);
|
|
45008
|
+
const names = new Set(assets.map((a) => a.name));
|
|
45009
|
+
for (const a of assets) {
|
|
45010
|
+
if (a.kind !== "toolset" && a.description.length < MIN_DESCRIPTION) add2("warning", "description", `The description is very short. Say what it does and when to use it.`, a.name);
|
|
45011
|
+
else if (a.kind !== "toolset" && !TRIGGER.test(a.description)) add2("warning", "description", `The description doesn't say when to use it ("Use when \u2026"), so harnesses may not load it.`, a.name);
|
|
45012
|
+
if (a.description.length >= 500) add2("warning", "description", "The description is cut at 500 characters.", a.name);
|
|
45013
|
+
const ns = a.name.split("/")[0];
|
|
45014
|
+
for (const dep of Object.keys(a.manifest.depends.skills ?? {})) {
|
|
45015
|
+
if (dep.startsWith(`${ns}/`) && !names.has(dep)) add2("warning", "dependency", `Uses skill ${dep}, which isn't in this repo. Fine if another repo in the org publishes it.`, a.name);
|
|
45016
|
+
}
|
|
45017
|
+
}
|
|
45018
|
+
return { assets: assets.map(({ manifest: _, ...a }) => a), findings };
|
|
45019
|
+
}
|
|
45020
|
+
async function repoLint(dir, opts) {
|
|
45021
|
+
const { assets, findings } = await lintRepo(dir, opts);
|
|
45022
|
+
const errors = findings.filter((f) => f.severity === "error").length;
|
|
45023
|
+
const warnings = findings.length - errors;
|
|
45024
|
+
if (opts.json) console.log(JSON.stringify({ assets, errors, warnings, findings }, null, 2));
|
|
45025
|
+
else {
|
|
45026
|
+
if (assets.length) ui.table(assets.map((a) => [ui.bold(a.name), a.kind, a.path, a.description.slice(0, 60)]), ["package", "kind", "path", "description"]);
|
|
45027
|
+
for (const f of findings) {
|
|
45028
|
+
const line = `${f.package ? `${ui.bold(f.package)} ` : ""}${f.message} ${ui.dim(`[${f.rule}]`)}`;
|
|
45029
|
+
if (f.severity === "error") ui.error(line);
|
|
45030
|
+
else ui.warn(line);
|
|
45031
|
+
}
|
|
45032
|
+
if (!findings.length) ui.ok(`Ready: ${assets.length} asset(s) will be published.`);
|
|
45033
|
+
}
|
|
45034
|
+
if (errors || opts.strict && warnings) {
|
|
45035
|
+
throw new CliError(`${errors} error(s), ${warnings} warning(s).`, errors ? "Assets with errors aren't published until they're fixed." : "Warnings fail the lint because of --strict.");
|
|
45036
|
+
}
|
|
45037
|
+
if (warnings && !opts.json) ui.info(`${warnings} warning(s). Pass --strict to fail on them.`);
|
|
45038
|
+
return { assets, findings };
|
|
45039
|
+
}
|
|
45040
|
+
|
|
45062
45041
|
// src/index.ts
|
|
45063
|
-
var VERSION = true ? "
|
|
45042
|
+
var VERSION = true ? "1.0.0" : "0.0.0-dev";
|
|
45064
45043
|
var act = (fn) => async (...a) => {
|
|
45065
45044
|
await fn(...a);
|
|
45066
45045
|
};
|
|
@@ -45069,30 +45048,24 @@ function buildProgram() {
|
|
|
45069
45048
|
const program2 = new Command().name("yarkr").description("Yarkr: install your org's skills, agents and MCP configs into every harness.").version(VERSION).option("-q, --quiet", "only print warnings and errors").hook("preAction", (cmd) => {
|
|
45070
45049
|
ui.quiet = !!cmd.opts().quiet;
|
|
45071
45050
|
});
|
|
45072
|
-
program2.command("login").description("
|
|
45073
|
-
program2.command("logout").description("forget the stored token").option("--registry <url>").action(act(logout));
|
|
45051
|
+
program2.command("login").description("sign in in the browser and keep a token in your keychain (or ~/.yarkrrc)").option("--registry <url>").option("--token <token>", "use this token instead of the browser (or pipe it on stdin)").option("--no-browser", "print a link to open on any device, then paste the token it shows").action(act(login));
|
|
45052
|
+
program2.command("logout").description("forget the stored token and revoke it on the server").option("--registry <url>").action(act(logout));
|
|
45074
45053
|
program2.command("whoami").description("show who you're signed in as").option("--registry <url>").action(act(whoami));
|
|
45075
|
-
program2.command("init").description("create yarkr.json (and .yarkrrc), detecting the harnesses used here").option("--harness <ids...>", "harnesses to target").option("--registry <url>", "registry to pin in .yarkrrc").option("--user", "install into your home directory instead of this project").option("--ark <refs...>", "install from these arks too, e.g. acme/finance
|
|
45054
|
+
program2.command("init").description("create yarkr.json (and .yarkrrc), detecting the harnesses used here").option("--harness <ids...>", "harnesses to target").option("--registry <url>", "registry to pin in .yarkrrc").option("--user", "install into your home directory instead of this project").option("--ark <refs...>", "install from these arks too, e.g. acme/finance @me, or another org's public ark").option("--force", "overwrite an existing yarkr.json").action(act(init2));
|
|
45076
45055
|
program2.command("search").argument("[query]").description("find packages").addOption(new Option("--kind <kind>").choices(["skill", "agent", "toolset"])).option("--target <harness>").option("--json").action(act(search));
|
|
45077
45056
|
program2.command("info").argument("<package>").description("show a package's channels, releases and owners").option("--json").action(act(info));
|
|
45078
|
-
program2.command("ark").argument("[arks...]", "limit to these arks, e.g. acme/finance or @me").description("show what your arks give you").option("--json").action(act((refs, o) => showArk(refs, o)));
|
|
45079
|
-
|
|
45080
|
-
|
|
45081
|
-
|
|
45082
|
-
|
|
45083
|
-
visibilityFlags(col.command("create").argument("<name>").description("create an empty collection (private unless you say otherwise)")).action(act(collectionCreate));
|
|
45084
|
-
visibilityFlags(col.command("edit").argument("<name>").description("change a collection's description or visibility")).action(act(collectionEdit));
|
|
45085
|
-
col.command("delete").argument("<name>").description("delete a collection and all its versions").action(act(collectionDelete));
|
|
45086
|
-
col.command("add").argument("<name>").argument("<arks...>", "@me, <org>/<ark>, global/<ark>, or a public ark").description("put arks in a collection (takes effect when you publish)").action(act(collectionAdd));
|
|
45087
|
-
col.command("remove").argument("<name>").argument("<arks...>").description("take arks out of a collection (takes effect when you publish)").action(act(collectionRemove));
|
|
45088
|
-
col.command("publish").argument("<name>").description("freeze the collection's arks into the next version, every package pinned").option("-m, --message <note>").option("--json").action(act(collectionPublish));
|
|
45089
|
-
col.command("arks").description("list public arks you can put in a collection").option("--json").action(act(collectionArks));
|
|
45057
|
+
const arkCmd = program2.command("ark").argument("[arks...]", "limit to these arks, e.g. acme/finance or @me").description("show what your arks give you").option("--json").action(act((refs, o) => showArk(refs, o)));
|
|
45058
|
+
arkCmd.command("lint").argument("<ark>", "an ark you can read, e.g. acme/finance").description("check an ark's items: missing or private packages, ranges that resolve to nothing, literal secrets, failing evals").option("--strict", "exit 1 on warnings too").option("--json").action(act((ref, o) => arkLint(ref, { ...o, json: o.json || !!arkCmd.opts().json })));
|
|
45059
|
+
program2.command("arks").description("list public arks: curated sets anyone can sync or connect over MCP").option("--json").action(act(publicArks));
|
|
45060
|
+
program2.command("lint").argument("[dir]", "a repo checkout", ".").description("check a repo is set up as a Yarkr source: what it publishes, problems the hub would refuse, and index typos or weak descriptions").option("--namespace <ns>", "namespace to show names in (default: the git owner)").option("--strict", "exit 1 on warnings too").option("--json").action(act(repoLint));
|
|
45061
|
+
program2.command("guide").argument("[name]", "a guide, e.g. create-ark; omit to list them").description("print instructions for your agent, e.g. how to build an ark for a topic").option("-o, --out <path>", "write to a file, or <dir>/SKILL.md for a directory (e.g. ~/.claude/skills/create-ark/)").option("--topic <topic>", "create-ark: what the ark is about").addOption(new Option("--type <type>", "create-ark: the kind of package it holds").choices(["skill", "agent", "mcp"])).action(act(guide));
|
|
45090
45062
|
syncFlags(program2.command("add").argument("<packages...>", "namespace/name[@range]").description("add packages to yarkr.json (outside a project: to your personal ark, or your user config when signed out) and sync").option("--no-sync", "only edit yarkr.json")).action(act((pkgs, o) => add(pkgs, { ...o, noSync: o.sync === false })));
|
|
45091
|
-
syncFlags(program2.command("remove").argument("<packages...>").description("remove packages (or opt out of optional ark items) and delete their files").option("--no-sync", "only edit yarkr.json")).action(act((pkgs, o) => remove(pkgs, { ...o, noSync: o.sync === false })));
|
|
45063
|
+
syncFlags(program2.command("remove").argument("<packages...>", "packages, or arks listed in yarkr.json").description("remove packages or arks (or opt out of optional ark items) and delete their files").option("--no-sync", "only edit yarkr.json")).action(act((pkgs, o) => remove(pkgs, { ...o, noSync: o.sync === false })));
|
|
45092
45064
|
syncFlags(program2.command("update").argument("[packages...]").description("move packages to the newest release their range allows")).action(act((pkgs, o) => update(pkgs, o)));
|
|
45093
45065
|
syncFlags(
|
|
45094
|
-
program2.command("sync").argument("[
|
|
45066
|
+
program2.command("sync").argument("[arks...]", "arks to add first: <org>/<ark>, yours or another org's public ark (which needs no sign-in)").description("install locked releases into each harness's native layout (outside a project: your arks, into your home directory)")
|
|
45095
45067
|
).action(act((refs, o) => sync(o, void 0, refs)));
|
|
45068
|
+
program2.command("yank").argument("<release>", "namespace/name@version").description("yank a release (org admins): ranges and stable skip it, exact pins still install it").option("--reason <text>", "why, shown to everyone who installed it").option("--undo", "un-yank it").action(act(yank));
|
|
45096
45069
|
program2.command("diff").argument("[package]").description("show local edits to synced files").option("--name-only").action(act(diff));
|
|
45097
45070
|
const evalCmd = program2.command("eval").argument("[dir]", "package folder", ".").description("check a package's eval suites (--local), or run them against a baseline (eval run)").option("--local", "validate the package and suites, and grade recorded outputs; no model calls").option("--outputs <dir>", "recorded outputs: <dir>/<suite>/<case>/{output.txt,transcript.json,files/}").option("--run-scripts", "run script graders (executes commands from the suite)").option("--json [file]", "print JSON (with run: write it to <file>)").action(
|
|
45098
45071
|
act(async (dir, o) => {
|
|
@@ -45109,7 +45082,7 @@ function buildProgram() {
|
|
|
45109
45082
|
);
|
|
45110
45083
|
const mcp = program2.command("mcp").description("connect harnesses to Yarkr's MCP server: one connection per org or team");
|
|
45111
45084
|
const mcpFlags = (c) => syncFlags(c).option("--token-env <name>", "environment variable holding the token for this connection (default YARKR_TOKEN)").option("--no-sync", "only edit the config");
|
|
45112
|
-
mcpFlags(mcp.command("add").argument("<scopes...>", "acme (an org), acme/finance (a team
|
|
45085
|
+
mcpFlags(mcp.command("add").argument("<scopes...>", "acme (an org), acme/finance (a team, or a public ark), all or public").description("add MCP connections and write them into each harness's MCP config")).action(
|
|
45113
45086
|
act((scopes, o) => mcpAdd(scopes, { ...o, noSync: o.sync === false }))
|
|
45114
45087
|
);
|
|
45115
45088
|
mcpFlags(mcp.command("remove").argument("<scopes...>").description("remove MCP connections from every harness")).action(act((scopes, o) => mcpRemove(scopes, { ...o, noSync: o.sync === false })));
|