@warmhub/cli 0.67.0 → 0.69.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/wh.js +1301 -552
- package/package.json +1 -1
package/dist/wh.js
CHANGED
|
@@ -18478,10 +18478,21 @@ var import_awaitAsyncGenerator = __toESM(require_awaitAsyncGenerator(), 1);
|
|
|
18478
18478
|
var import_wrapAsyncGenerator = __toESM(require_wrapAsyncGenerator(), 1);
|
|
18479
18479
|
var import_objectSpread29 = __toESM(require_objectSpread2(), 1);
|
|
18480
18480
|
// ../../packages/rules/src/builtin-shapes.ts
|
|
18481
|
-
var BUILTIN_SHAPE_NAMES = ["Pair", "
|
|
18481
|
+
var BUILTIN_SHAPE_NAMES = ["Pair", "Set", "List"];
|
|
18482
|
+
var RETIRED_COLLECTION_SHAPE_NAMES = ["Triple"];
|
|
18483
|
+
var RESERVED_COLLECTION_SHAPE_NAMES = [
|
|
18484
|
+
...BUILTIN_SHAPE_NAMES,
|
|
18485
|
+
...RETIRED_COLLECTION_SHAPE_NAMES
|
|
18486
|
+
];
|
|
18482
18487
|
function isBuiltinCollectionShape(name) {
|
|
18483
18488
|
return BUILTIN_SHAPE_NAMES.includes(name);
|
|
18484
18489
|
}
|
|
18490
|
+
function isRetiredCollectionShape(name) {
|
|
18491
|
+
return RETIRED_COLLECTION_SHAPE_NAMES.includes(name);
|
|
18492
|
+
}
|
|
18493
|
+
function isReservedCollectionShape(name) {
|
|
18494
|
+
return RESERVED_COLLECTION_SHAPE_NAMES.includes(name);
|
|
18495
|
+
}
|
|
18485
18496
|
var BUILTIN_CONTENT_SHAPE_NAMES = ["Content"];
|
|
18486
18497
|
var STORED_CONTENT_NAMES = ["Readme", "Agents"];
|
|
18487
18498
|
var SYNTHESIZED_CONTENT_NAMES = ["LlmsTxt"];
|
|
@@ -18499,14 +18510,6 @@ var BUILTIN_SHAPE_DEFS = {
|
|
|
18499
18510
|
},
|
|
18500
18511
|
description: "An ordered pair of two things"
|
|
18501
18512
|
},
|
|
18502
|
-
Triple: {
|
|
18503
|
-
fields: {
|
|
18504
|
-
first: { type: "wref", description: "First member of the triple" },
|
|
18505
|
-
second: { type: "wref", description: "Second member of the triple" },
|
|
18506
|
-
third: { type: "wref", description: "Third member of the triple" }
|
|
18507
|
-
},
|
|
18508
|
-
description: "An ordered triple of three things"
|
|
18509
|
-
},
|
|
18510
18513
|
Set: {
|
|
18511
18514
|
fields: {
|
|
18512
18515
|
members: [{ type: "wref", description: "Members of the set" }]
|
|
@@ -18553,36 +18556,6 @@ var COMMIT_OPERATION_KINDS = [
|
|
|
18553
18556
|
"assertion",
|
|
18554
18557
|
"collection"
|
|
18555
18558
|
];
|
|
18556
|
-
function isCollectionAbout(value) {
|
|
18557
|
-
if (typeof value !== "object" || value === null || Array.isArray(value))
|
|
18558
|
-
return false;
|
|
18559
|
-
const record = value;
|
|
18560
|
-
const keys = Object.keys(record);
|
|
18561
|
-
if (keys.length !== 1)
|
|
18562
|
-
return false;
|
|
18563
|
-
const key = keys[0];
|
|
18564
|
-
if (key !== "pair" && key !== "triple" && key !== "set" && key !== "list")
|
|
18565
|
-
return false;
|
|
18566
|
-
return Array.isArray(record[key]);
|
|
18567
|
-
}
|
|
18568
|
-
function collectionAboutType(about) {
|
|
18569
|
-
if ("pair" in about)
|
|
18570
|
-
return "pair";
|
|
18571
|
-
if ("triple" in about)
|
|
18572
|
-
return "triple";
|
|
18573
|
-
if ("set" in about)
|
|
18574
|
-
return "set";
|
|
18575
|
-
return "list";
|
|
18576
|
-
}
|
|
18577
|
-
function collectionAboutMembers(about) {
|
|
18578
|
-
if ("pair" in about)
|
|
18579
|
-
return about.pair;
|
|
18580
|
-
if ("triple" in about)
|
|
18581
|
-
return about.triple;
|
|
18582
|
-
if ("set" in about)
|
|
18583
|
-
return about.set;
|
|
18584
|
-
return about.list;
|
|
18585
|
-
}
|
|
18586
18559
|
function splitLocalPath(name) {
|
|
18587
18560
|
const idx = name.indexOf("/");
|
|
18588
18561
|
if (idx === -1)
|
|
@@ -18645,6 +18618,26 @@ function stableJsonEquals(left, right) {
|
|
|
18645
18618
|
return stableJson(left) === stableJson(right);
|
|
18646
18619
|
}
|
|
18647
18620
|
|
|
18621
|
+
// ../../packages/rules/src/subscribable-events.ts
|
|
18622
|
+
var COMMIT_EVENT_TYPE = "commit";
|
|
18623
|
+
var REPO_RENAMED_EVENT_TYPE = "repo.renamed";
|
|
18624
|
+
var ORG_RENAMED_EVENT_TYPE = "org.renamed";
|
|
18625
|
+
var THING_RENAMED_EVENT_TYPE = "thing.renamed";
|
|
18626
|
+
var SHAPE_RENAMED_EVENT_TYPE = "shape.renamed";
|
|
18627
|
+
var SUBSCRIBABLE_EVENT_TYPES = [
|
|
18628
|
+
COMMIT_EVENT_TYPE,
|
|
18629
|
+
REPO_RENAMED_EVENT_TYPE,
|
|
18630
|
+
ORG_RENAMED_EVENT_TYPE,
|
|
18631
|
+
THING_RENAMED_EVENT_TYPE,
|
|
18632
|
+
SHAPE_RENAMED_EVENT_TYPE
|
|
18633
|
+
];
|
|
18634
|
+
var REPO_SCOPED_EVENT_TYPES = [
|
|
18635
|
+
COMMIT_EVENT_TYPE,
|
|
18636
|
+
REPO_RENAMED_EVENT_TYPE,
|
|
18637
|
+
THING_RENAMED_EVENT_TYPE,
|
|
18638
|
+
SHAPE_RENAMED_EVENT_TYPE
|
|
18639
|
+
];
|
|
18640
|
+
|
|
18648
18641
|
// ../../packages/rules/src/component-install.ts
|
|
18649
18642
|
function manifestShapeData(shape) {
|
|
18650
18643
|
const data = { fields: shape.fields };
|
|
@@ -19195,6 +19188,24 @@ function validateCredential(cred, i, errors) {
|
|
|
19195
19188
|
}
|
|
19196
19189
|
validateProvisioning(cred, path, errors);
|
|
19197
19190
|
}
|
|
19191
|
+
function validateEventTrigger(trigger, path, errors) {
|
|
19192
|
+
const event = trigger.event;
|
|
19193
|
+
if (event !== undefined) {
|
|
19194
|
+
if (typeof event !== "string" || !REPO_SCOPED_EVENT_TYPES.includes(event)) {
|
|
19195
|
+
errors.push(`${path}.event must be one of: ${REPO_SCOPED_EVENT_TYPES.join(", ")}`);
|
|
19196
|
+
return;
|
|
19197
|
+
}
|
|
19198
|
+
}
|
|
19199
|
+
if (event === undefined || event === COMMIT_EVENT_TYPE) {
|
|
19200
|
+
requireString(trigger, "shape", path, errors);
|
|
19201
|
+
return;
|
|
19202
|
+
}
|
|
19203
|
+
for (const field of ["shape", "filter"]) {
|
|
19204
|
+
if (trigger[field] !== undefined) {
|
|
19205
|
+
errors.push(`${path}.${field} is not valid for a "${event}" trigger — metadata events have no shape or filter`);
|
|
19206
|
+
}
|
|
19207
|
+
}
|
|
19208
|
+
}
|
|
19198
19209
|
function validateSubscription(sub, i, errors) {
|
|
19199
19210
|
const path = `manifest.subscriptions[${i}]`;
|
|
19200
19211
|
if (!isObject2(sub)) {
|
|
@@ -19215,7 +19226,7 @@ function validateSubscription(sub, i, errors) {
|
|
|
19215
19226
|
errors.push(`${path}.trigger must be an object`);
|
|
19216
19227
|
} else {
|
|
19217
19228
|
if (sub.trigger.kind === "event") {
|
|
19218
|
-
|
|
19229
|
+
validateEventTrigger(sub.trigger, `${path}.trigger`, errors);
|
|
19219
19230
|
} else if (sub.trigger.kind === "cron") {
|
|
19220
19231
|
errors.push(`${path}.trigger.kind "cron" is no longer supported; cron subscriptions were removed from the public surface — use an "event" trigger`);
|
|
19221
19232
|
} else {
|
|
@@ -19434,7 +19445,7 @@ function validateManifestSemantics(manifest) {
|
|
|
19434
19445
|
]);
|
|
19435
19446
|
const knownSeedShapes = new Set([...shapeNames, "ComponentConfig"]);
|
|
19436
19447
|
for (const sub of manifest.subscriptions) {
|
|
19437
|
-
if (sub.trigger.kind === "event" && !knownSubscriptionTriggerShapes.has(sub.trigger.shape)) {
|
|
19448
|
+
if (sub.trigger.kind === "event" && sub.trigger.shape !== undefined && !knownSubscriptionTriggerShapes.has(sub.trigger.shape)) {
|
|
19438
19449
|
findings.push({
|
|
19439
19450
|
level: "error",
|
|
19440
19451
|
code: "MISSING_SUBSCRIPTION_TRIGGER_SHAPE_REF",
|
|
@@ -19949,9 +19960,99 @@ var PLATFORM_STATUS_PROBE_ARTIFACT_FIELDS = {
|
|
|
19949
19960
|
description: "Optional URL associated with this artifact."
|
|
19950
19961
|
}
|
|
19951
19962
|
};
|
|
19963
|
+
// ../../packages/rules/src/tokens.ts
|
|
19964
|
+
var COMMIT_TOKEN_SYNTAX_REMOVED_MESSAGE = "$N/#N commit-token syntax is no longer supported. Use explicit names and explicit wrefs. For assertions about newly created things, create the thing with a deterministic name and set about to that wref in the same commit.";
|
|
19965
|
+
var ANY_TOKEN_RE = /[$#]\d+/;
|
|
19966
|
+
function hasAnyTokens(s) {
|
|
19967
|
+
return ANY_TOKEN_RE.test(s);
|
|
19968
|
+
}
|
|
19969
|
+
|
|
19970
|
+
// ../../packages/rules/src/preflight-commit.ts
|
|
19971
|
+
function preflightCommitDiagnostics(operations, options) {
|
|
19972
|
+
const errors = [];
|
|
19973
|
+
rejectCommitTokenSyntax(operations, errors);
|
|
19974
|
+
illegalOpSequences(operations, errors, options?.checkAddAdd ?? true);
|
|
19975
|
+
return errors;
|
|
19976
|
+
}
|
|
19977
|
+
function getOpName(op) {
|
|
19978
|
+
return op.name;
|
|
19979
|
+
}
|
|
19980
|
+
function tokenStringFields(op) {
|
|
19981
|
+
const fields = [getOpName(op), op.newName];
|
|
19982
|
+
if (typeof op.about === "string") {
|
|
19983
|
+
fields.push(op.about);
|
|
19984
|
+
}
|
|
19985
|
+
if (op.members) {
|
|
19986
|
+
fields.push(...op.members);
|
|
19987
|
+
}
|
|
19988
|
+
return fields;
|
|
19989
|
+
}
|
|
19990
|
+
function rejectCommitTokenSyntax(operations, errors) {
|
|
19991
|
+
for (let i = 0;i < operations.length; i++) {
|
|
19992
|
+
const op = operations[i];
|
|
19993
|
+
if (!op)
|
|
19994
|
+
continue;
|
|
19995
|
+
for (const field of tokenStringFields(op)) {
|
|
19996
|
+
if (field && hasAnyTokens(field)) {
|
|
19997
|
+
errors.push({
|
|
19998
|
+
code: "COMMIT_TOKEN_SYNTAX_REMOVED",
|
|
19999
|
+
operationIndex: i,
|
|
20000
|
+
message: COMMIT_TOKEN_SYNTAX_REMOVED_MESSAGE
|
|
20001
|
+
});
|
|
20002
|
+
break;
|
|
20003
|
+
}
|
|
20004
|
+
}
|
|
20005
|
+
}
|
|
20006
|
+
}
|
|
20007
|
+
function illegalOpSequences(operations, errors, checkAddAdd) {
|
|
20008
|
+
const opHistory = new Map;
|
|
20009
|
+
for (let i = 0;i < operations.length; i++) {
|
|
20010
|
+
const op = operations[i];
|
|
20011
|
+
if (!op)
|
|
20012
|
+
continue;
|
|
20013
|
+
const name = getOpName(op);
|
|
20014
|
+
if (!name)
|
|
20015
|
+
continue;
|
|
20016
|
+
if (hasAnyTokens(name))
|
|
20017
|
+
continue;
|
|
20018
|
+
const kind = inferOperationKind({ ...op, name });
|
|
20019
|
+
const qualName = kind === "shape" ? `shape:${name}` : `thing:${name}`;
|
|
20020
|
+
const history = opHistory.get(qualName) ?? [];
|
|
20021
|
+
history.push({ operation: op.operation, index: i });
|
|
20022
|
+
opHistory.set(qualName, history);
|
|
20023
|
+
}
|
|
20024
|
+
for (const [qualName, history] of opHistory) {
|
|
20025
|
+
if (history.length < 2)
|
|
20026
|
+
continue;
|
|
20027
|
+
for (let i = 1;i < history.length; i++) {
|
|
20028
|
+
const prev = history[i - 1];
|
|
20029
|
+
const curr = history[i];
|
|
20030
|
+
if (!prev || !curr)
|
|
20031
|
+
continue;
|
|
20032
|
+
const pair = `${prev.operation}+${curr.operation}`;
|
|
20033
|
+
if (checkAddAdd && pair === "add+add") {
|
|
20034
|
+
errors.push({
|
|
20035
|
+
code: "ILLEGAL_OP_SEQUENCE",
|
|
20036
|
+
operationIndex: curr.index,
|
|
20037
|
+
message: `Cannot add "${qualName}" twice in the same commit`
|
|
20038
|
+
});
|
|
20039
|
+
}
|
|
20040
|
+
if (pair === "revise+add") {
|
|
20041
|
+
errors.push({
|
|
20042
|
+
code: "ILLEGAL_OP_SEQUENCE",
|
|
20043
|
+
operationIndex: curr.index,
|
|
20044
|
+
message: `Cannot revise then add "${qualName}" in the same commit`
|
|
20045
|
+
});
|
|
20046
|
+
}
|
|
20047
|
+
}
|
|
20048
|
+
}
|
|
20049
|
+
}
|
|
20050
|
+
|
|
19952
20051
|
// ../../packages/rules/src/preflight-operation.ts
|
|
19953
|
-
var collectionTypes = ["pair", "
|
|
20052
|
+
var collectionTypes = ["pair", "set", "list"];
|
|
19954
20053
|
var collectionOps = ["add", "revise"];
|
|
20054
|
+
var COLLECTION_CREATE_REQUIRES_NAME_MESSAGE = "Collection create requires a name. Collections are ordinary named things (ADR 0004).";
|
|
20055
|
+
var COLLECTION_ABOUT_REMOVED_MESSAGE = 'about accepts a wref. Create the collection as its own named operation, then point the assertion at it. Prefer deterministic relationship names, for example: [{"operation":"add","kind":"collection","type":"pair","name":"a-b-relationship","members":["A","B"]},{"operation":"add","kind":"assertion","about":"Pair/a-b-relationship","name":"Assertion/example","data":{}}]. For CLI usage, use wh commit submit --file with the two operations.';
|
|
19955
20056
|
function preflightOpDiagnostics(op, operationIndex) {
|
|
19956
20057
|
const errors = [];
|
|
19957
20058
|
errors.push(...builtinShapeGuard(op, operationIndex));
|
|
@@ -19964,17 +20065,41 @@ function preflightOpDiagnostics(op, operationIndex) {
|
|
|
19964
20065
|
function builtinShapeGuard(op, operationIndex) {
|
|
19965
20066
|
const errors = [];
|
|
19966
20067
|
const name = op.name;
|
|
19967
|
-
if (
|
|
20068
|
+
if (name && isRetiredCollectionShape(name)) {
|
|
20069
|
+
errors.push({
|
|
20070
|
+
code: "RESERVED_NAME",
|
|
20071
|
+
operationIndex,
|
|
20072
|
+
message: `Shape "${name}" is a retired collection shape and cannot be written manually`
|
|
20073
|
+
});
|
|
20074
|
+
}
|
|
20075
|
+
if (op.operation === "rename" && (op.kind === "shape" || op.name !== undefined && !splitLocalPath(op.name)) && op.newName && isRetiredCollectionShape(op.newName)) {
|
|
19968
20076
|
errors.push({
|
|
19969
20077
|
code: "RESERVED_NAME",
|
|
19970
20078
|
operationIndex,
|
|
19971
|
-
message: `Shape "${
|
|
20079
|
+
message: `Shape "${op.newName}" is a retired collection shape and cannot be written manually`
|
|
19972
20080
|
});
|
|
20081
|
+
} else {
|
|
20082
|
+
const isShapeRename = op.operation === "rename" && (op.kind === "shape" || op.name !== undefined && !splitLocalPath(op.name));
|
|
20083
|
+
const builtinShapeName = name && isBuiltinShape(name) ? name : isShapeRename && op.newName && isBuiltinShape(op.newName) ? op.newName : undefined;
|
|
20084
|
+
if (builtinShapeName && (isShapeRename || op.operation !== "retract" && op.kind === "shape")) {
|
|
20085
|
+
const action = op.operation === "add" ? "created" : op.operation === "rename" ? "renamed" : "revised";
|
|
20086
|
+
errors.push({
|
|
20087
|
+
code: "RESERVED_NAME",
|
|
20088
|
+
operationIndex,
|
|
20089
|
+
message: `Shape "${builtinShapeName}" is a built-in shape and cannot be ${action} manually`
|
|
20090
|
+
});
|
|
20091
|
+
}
|
|
19973
20092
|
}
|
|
19974
|
-
if (
|
|
20093
|
+
if (name) {
|
|
19975
20094
|
const local = splitLocalPath(name);
|
|
19976
|
-
if (local &&
|
|
19977
|
-
|
|
20095
|
+
if (local && isRetiredCollectionShape(local.shapePrefix)) {
|
|
20096
|
+
errors.push({
|
|
20097
|
+
code: "VALIDATION_ERROR",
|
|
20098
|
+
operationIndex,
|
|
20099
|
+
message: `Cannot ${op.operation} under retired collection shape "${local.shapePrefix}". Triple is read-only and retired for new collection writes.`
|
|
20100
|
+
});
|
|
20101
|
+
} else if (op.kind === "thing" && local && isBuiltinCollectionShape(local.shapePrefix)) {
|
|
20102
|
+
const message = op.operation === "add" ? `Cannot add kind="thing" under built-in shape "${local.shapePrefix}". Use kind="collection" instead.` : `Cannot revise kind="thing" under built-in shape "${local.shapePrefix}". Use kind="collection" to revise a collection.`;
|
|
19978
20103
|
errors.push({
|
|
19979
20104
|
code: "VALIDATION_ERROR",
|
|
19980
20105
|
operationIndex,
|
|
@@ -20014,16 +20139,32 @@ function contentNameGuard(op, operationIndex) {
|
|
|
20014
20139
|
function plusSignGuard(op, operationIndex) {
|
|
20015
20140
|
const errors = [];
|
|
20016
20141
|
const name = op.name;
|
|
20017
|
-
if (op.
|
|
20142
|
+
if (op.newName?.includes("+")) {
|
|
20143
|
+
errors.push({
|
|
20144
|
+
code: "VALIDATION_ERROR",
|
|
20145
|
+
operationIndex,
|
|
20146
|
+
message: `Name "${op.newName}" contains reserved character "+". The "+" character is reserved for the historical collection auto-name namespace and is not allowed in user-supplied names.`
|
|
20147
|
+
});
|
|
20018
20148
|
return errors;
|
|
20149
|
+
}
|
|
20019
20150
|
if (name?.includes("+")) {
|
|
20151
|
+
if (op.kind === "collection" && op.operation === "add") {
|
|
20152
|
+
errors.push({
|
|
20153
|
+
code: "VALIDATION_ERROR",
|
|
20154
|
+
operationIndex,
|
|
20155
|
+
message: `Name "${name}" contains reserved character "+". The "+" character is reserved for the historical collection auto-name namespace and is not allowed in user-supplied names.`
|
|
20156
|
+
});
|
|
20157
|
+
return errors;
|
|
20158
|
+
}
|
|
20159
|
+
if (op.kind === "collection")
|
|
20160
|
+
return errors;
|
|
20020
20161
|
const local = splitLocalPath(name);
|
|
20021
|
-
if (local &&
|
|
20162
|
+
if (local && isReservedCollectionShape(local.shapePrefix))
|
|
20022
20163
|
return errors;
|
|
20023
20164
|
errors.push({
|
|
20024
20165
|
code: "VALIDATION_ERROR",
|
|
20025
20166
|
operationIndex,
|
|
20026
|
-
message: `Name "${name}" contains reserved character "+". The "+" character is reserved for collection names.`
|
|
20167
|
+
message: `Name "${name}" contains reserved character "+". The "+" character is reserved for the historical collection auto-name namespace and is not allowed in user-supplied names.`
|
|
20027
20168
|
});
|
|
20028
20169
|
}
|
|
20029
20170
|
return errors;
|
|
@@ -20032,102 +20173,79 @@ function validateCollectionAbouts(op, operationIndex) {
|
|
|
20032
20173
|
const errors = [];
|
|
20033
20174
|
if (!op.about || typeof op.about === "string")
|
|
20034
20175
|
return errors;
|
|
20035
|
-
|
|
20036
|
-
|
|
20176
|
+
errors.push({
|
|
20177
|
+
code: "VALIDATION_ERROR",
|
|
20178
|
+
operationIndex,
|
|
20179
|
+
message: COLLECTION_ABOUT_REMOVED_MESSAGE
|
|
20180
|
+
});
|
|
20181
|
+
return errors;
|
|
20182
|
+
}
|
|
20183
|
+
function validateCollectionOps(op, operationIndex) {
|
|
20184
|
+
const errors = [];
|
|
20185
|
+
if (op.kind !== "collection")
|
|
20186
|
+
return errors;
|
|
20187
|
+
if (!collectionOps.includes(op.operation)) {
|
|
20188
|
+
return errors;
|
|
20189
|
+
}
|
|
20190
|
+
if (op.operation === "add" && !op.name) {
|
|
20037
20191
|
errors.push({
|
|
20038
20192
|
code: "VALIDATION_ERROR",
|
|
20039
20193
|
operationIndex,
|
|
20040
|
-
message:
|
|
20194
|
+
message: COLLECTION_CREATE_REQUIRES_NAME_MESSAGE
|
|
20041
20195
|
});
|
|
20042
|
-
return errors;
|
|
20043
|
-
}
|
|
20044
|
-
const tag = collectionAboutType(op.about);
|
|
20045
|
-
const members = collectionAboutMembers(op.about);
|
|
20046
|
-
for (let i = 0;i < members.length; i++) {
|
|
20047
|
-
if (typeof members[i] !== "string") {
|
|
20048
|
-
errors.push({
|
|
20049
|
-
code: "VALIDATION_ERROR",
|
|
20050
|
-
operationIndex,
|
|
20051
|
-
message: `Collection member at index ${i} must be a string, got ${typeof members[i]}`
|
|
20052
|
-
});
|
|
20053
|
-
}
|
|
20054
20196
|
}
|
|
20055
|
-
|
|
20056
|
-
if (arityError) {
|
|
20197
|
+
if (!op.type || !collectionTypes.includes(op.type)) {
|
|
20057
20198
|
errors.push({
|
|
20058
20199
|
code: "VALIDATION_ERROR",
|
|
20059
20200
|
operationIndex,
|
|
20060
|
-
message:
|
|
20201
|
+
message: `Collection "type" must be one of: pair, set, list. Got: "${op.type ?? ""}"`
|
|
20061
20202
|
});
|
|
20062
20203
|
}
|
|
20063
|
-
|
|
20064
|
-
}
|
|
20065
|
-
function validateCollectionOps(op, operationIndex) {
|
|
20066
|
-
const errors = [];
|
|
20067
|
-
if (op.kind !== "collection")
|
|
20068
|
-
return errors;
|
|
20069
|
-
if (!collectionOps.includes(op.operation)) {
|
|
20204
|
+
if (!op.members || !Array.isArray(op.members)) {
|
|
20070
20205
|
errors.push({
|
|
20071
20206
|
code: "VALIDATION_ERROR",
|
|
20072
20207
|
operationIndex,
|
|
20073
|
-
message:
|
|
20208
|
+
message: 'Collection requires a "members" array'
|
|
20074
20209
|
});
|
|
20075
|
-
|
|
20076
|
-
|
|
20077
|
-
|
|
20078
|
-
if (!op.type || !collectionTypes.includes(op.type)) {
|
|
20079
|
-
errors.push({
|
|
20080
|
-
code: "VALIDATION_ERROR",
|
|
20081
|
-
operationIndex,
|
|
20082
|
-
message: `Collection "type" must be one of: pair, triple, set, list. Got: "${op.type ?? ""}"`
|
|
20083
|
-
});
|
|
20084
|
-
}
|
|
20085
|
-
if (!op.members || !Array.isArray(op.members)) {
|
|
20086
|
-
errors.push({
|
|
20087
|
-
code: "VALIDATION_ERROR",
|
|
20088
|
-
operationIndex,
|
|
20089
|
-
message: 'Collection requires a "members" array'
|
|
20090
|
-
});
|
|
20091
|
-
} else {
|
|
20092
|
-
for (let i = 0;i < op.members.length; i++) {
|
|
20093
|
-
if (typeof op.members[i] !== "string") {
|
|
20094
|
-
errors.push({
|
|
20095
|
-
code: "VALIDATION_ERROR",
|
|
20096
|
-
operationIndex,
|
|
20097
|
-
message: `Collection member at index ${i} must be a string`
|
|
20098
|
-
});
|
|
20099
|
-
}
|
|
20100
|
-
}
|
|
20101
|
-
}
|
|
20102
|
-
if (op.type && op.members) {
|
|
20103
|
-
const arityError = collectionArityError(op.type, op.members);
|
|
20104
|
-
if (arityError) {
|
|
20210
|
+
} else {
|
|
20211
|
+
for (let i = 0;i < op.members.length; i++) {
|
|
20212
|
+
if (typeof op.members[i] !== "string") {
|
|
20105
20213
|
errors.push({
|
|
20106
20214
|
code: "VALIDATION_ERROR",
|
|
20107
20215
|
operationIndex,
|
|
20108
|
-
message:
|
|
20216
|
+
message: `Collection member at index ${i} must be a string`
|
|
20109
20217
|
});
|
|
20110
20218
|
}
|
|
20111
20219
|
}
|
|
20112
20220
|
}
|
|
20221
|
+
if (op.type && op.members) {
|
|
20222
|
+
const arityError = collectionArityError(op.type, op.members);
|
|
20223
|
+
if (arityError) {
|
|
20224
|
+
errors.push({
|
|
20225
|
+
code: "VALIDATION_ERROR",
|
|
20226
|
+
operationIndex,
|
|
20227
|
+
message: arityError
|
|
20228
|
+
});
|
|
20229
|
+
}
|
|
20230
|
+
}
|
|
20113
20231
|
return errors;
|
|
20114
20232
|
}
|
|
20115
20233
|
function collectionArityError(tag, members) {
|
|
20116
20234
|
switch (tag) {
|
|
20117
20235
|
case "pair":
|
|
20118
20236
|
return members.length !== 2 ? `Pair requires exactly 2 members, got ${members.length}` : null;
|
|
20119
|
-
case "triple":
|
|
20120
|
-
return members.length !== 3 ? `Triple requires exactly 3 members, got ${members.length}` : null;
|
|
20121
20237
|
case "set":
|
|
20122
20238
|
case "list":
|
|
20123
20239
|
return members.length < 1 ? `${tag === "set" ? "Set" : "List"} requires at least 1 member, got 0` : null;
|
|
20124
20240
|
}
|
|
20125
20241
|
}
|
|
20126
|
-
|
|
20127
20242
|
// ../../packages/rules/src/preflight.ts
|
|
20128
20243
|
function preflightOpDiagnostics2(op, operationIndex) {
|
|
20129
20244
|
return preflightOpDiagnostics(op, operationIndex);
|
|
20130
20245
|
}
|
|
20246
|
+
function preflightCommitDiagnostics2(operations, options) {
|
|
20247
|
+
return preflightCommitDiagnostics(operations, options);
|
|
20248
|
+
}
|
|
20131
20249
|
// ../../packages/rules/src/reserved-orgs.ts
|
|
20132
20250
|
var RESERVED_RAW_CONTENT_TOP_LEVEL_NAMES = [
|
|
20133
20251
|
"_app",
|
|
@@ -27281,15 +27399,6 @@ function validateShapeDefinition(data, options = {}) {
|
|
|
27281
27399
|
}
|
|
27282
27400
|
return { valid: true };
|
|
27283
27401
|
}
|
|
27284
|
-
// ../../packages/rules/src/subscribable-events.ts
|
|
27285
|
-
var COMMIT_EVENT_TYPE = "commit";
|
|
27286
|
-
var REPO_RENAMED_EVENT_TYPE = "repo.renamed";
|
|
27287
|
-
var ORG_RENAMED_EVENT_TYPE = "org.renamed";
|
|
27288
|
-
var SUBSCRIBABLE_EVENT_TYPES = [
|
|
27289
|
-
COMMIT_EVENT_TYPE,
|
|
27290
|
-
REPO_RENAMED_EVENT_TYPE,
|
|
27291
|
-
ORG_RENAMED_EVENT_TYPE
|
|
27292
|
-
];
|
|
27293
27402
|
// ../../packages/rules/src/system-components/system.ts
|
|
27294
27403
|
var SYSTEM_COMPONENT_ID = "com.warmhub.system";
|
|
27295
27404
|
var COMPONENT_INSTALL_FIELDS = {
|
|
@@ -27352,7 +27461,7 @@ function findSystemComponent(componentId) {
|
|
|
27352
27461
|
// ../../packages/sdk-ts/package.json
|
|
27353
27462
|
var package_default = {
|
|
27354
27463
|
name: "@warmhub/sdk-ts",
|
|
27355
|
-
version: "0.
|
|
27464
|
+
version: "0.68.0",
|
|
27356
27465
|
private: false,
|
|
27357
27466
|
type: "module",
|
|
27358
27467
|
description: "The TypeScript SDK for WarmHub — create repos, commit and query data, and compound knowledge with your AI agents.",
|
|
@@ -27460,16 +27569,38 @@ function shapeDefinitionPreflightError(name, data, verb) {
|
|
|
27460
27569
|
}
|
|
27461
27570
|
|
|
27462
27571
|
// ../../packages/sdk-ts/src/collection-operation-normalize.ts
|
|
27463
|
-
var collectionTypes2 = new Set([
|
|
27464
|
-
"pair",
|
|
27465
|
-
"triple",
|
|
27466
|
-
"set",
|
|
27467
|
-
"list"
|
|
27468
|
-
]);
|
|
27572
|
+
var collectionTypes2 = new Set(["pair", "set", "list"]);
|
|
27469
27573
|
function normalizeBackendCollectionAdd(operation, source) {
|
|
27470
|
-
const
|
|
27574
|
+
const normalized = normalizeCollectionWrite(operation, source, "add");
|
|
27575
|
+
return {
|
|
27471
27576
|
operation: "add",
|
|
27472
27577
|
kind: "collection",
|
|
27578
|
+
name: normalized.name,
|
|
27579
|
+
type: normalized.type,
|
|
27580
|
+
members: normalized.members,
|
|
27581
|
+
...operation.skipExisting === true ? { skipExisting: true } : {}
|
|
27582
|
+
};
|
|
27583
|
+
}
|
|
27584
|
+
function normalizeBackendCollectionRevise(operation, source) {
|
|
27585
|
+
const normalized = normalizeCollectionWrite(operation, source, "revise");
|
|
27586
|
+
if (!normalized.name) {
|
|
27587
|
+
throw new Error(`${source}: collection revise requires a target name`);
|
|
27588
|
+
}
|
|
27589
|
+
return {
|
|
27590
|
+
operation: "revise",
|
|
27591
|
+
kind: "collection",
|
|
27592
|
+
name: normalized.name,
|
|
27593
|
+
type: normalized.type,
|
|
27594
|
+
members: normalized.members,
|
|
27595
|
+
...typeof operation.expectedVersion === "number" ? { expectedVersion: operation.expectedVersion } : {},
|
|
27596
|
+
...typeof operation.leaseId === "string" && operation.leaseId.length > 0 ? { leaseId: operation.leaseId } : {}
|
|
27597
|
+
};
|
|
27598
|
+
}
|
|
27599
|
+
function normalizeCollectionWrite(operation, source, writeOperation) {
|
|
27600
|
+
const diagnostics = preflightOpDiagnostics2({
|
|
27601
|
+
operation: writeOperation,
|
|
27602
|
+
kind: "collection",
|
|
27603
|
+
name: typeof operation.name === "string" ? operation.name : undefined,
|
|
27473
27604
|
type: typeof operation.type === "string" ? operation.type : undefined,
|
|
27474
27605
|
members: Array.isArray(operation.members) ? operation.members : undefined
|
|
27475
27606
|
}, 0);
|
|
@@ -27478,29 +27609,32 @@ function normalizeBackendCollectionAdd(operation, source) {
|
|
|
27478
27609
|
}
|
|
27479
27610
|
const type = normalizeCollectionType(operation.type);
|
|
27480
27611
|
if (!type) {
|
|
27481
|
-
throw new Error(`${source}: collection
|
|
27612
|
+
throw new Error(`${source}: collection ${writeOperation} requires 'type' to be one of: pair, set, list`);
|
|
27482
27613
|
}
|
|
27483
27614
|
if (!Array.isArray(operation.members)) {
|
|
27484
|
-
throw new Error(`${source}: collection
|
|
27615
|
+
throw new Error(`${source}: collection ${writeOperation} requires a 'members' array`);
|
|
27485
27616
|
}
|
|
27486
27617
|
const name = normalizeOptionalName(operation.name);
|
|
27487
|
-
if (
|
|
27488
|
-
throw new Error(`${source}: collection
|
|
27618
|
+
if (!name) {
|
|
27619
|
+
throw new Error(`${source}: collection ${writeOperation} name must be a non-empty string`);
|
|
27489
27620
|
}
|
|
27490
|
-
|
|
27621
|
+
assertNoUnsupportedCollectionFields(operation, source, writeOperation);
|
|
27491
27622
|
return {
|
|
27492
|
-
|
|
27493
|
-
kind: "collection",
|
|
27494
|
-
...name ? { name } : {},
|
|
27623
|
+
name,
|
|
27495
27624
|
type,
|
|
27496
|
-
members: operation.members
|
|
27497
|
-
...operation.skipExisting === true ? { skipExisting: true } : {}
|
|
27625
|
+
members: operation.members
|
|
27498
27626
|
};
|
|
27499
27627
|
}
|
|
27500
|
-
function
|
|
27501
|
-
const unsupportedFields = [
|
|
27628
|
+
function assertNoUnsupportedCollectionFields(operation, source, writeOperation) {
|
|
27629
|
+
const unsupportedFields = [
|
|
27630
|
+
"about",
|
|
27631
|
+
"aboutWref",
|
|
27632
|
+
"shapeWref",
|
|
27633
|
+
"data",
|
|
27634
|
+
...writeOperation === "revise" ? ["skipExisting"] : []
|
|
27635
|
+
].filter((field) => operation[field] !== undefined);
|
|
27502
27636
|
if (unsupportedFields.length > 0) {
|
|
27503
|
-
throw new Error(`${source}: collection
|
|
27637
|
+
throw new Error(`${source}: collection ${writeOperation} does not support ${unsupportedFields.map((field) => `'${field}'`).join(", ")}`);
|
|
27504
27638
|
}
|
|
27505
27639
|
}
|
|
27506
27640
|
function normalizeCollectionType(value) {
|
|
@@ -27550,12 +27684,12 @@ function toBackendStreamOperation(operation) {
|
|
|
27550
27684
|
if (Object.hasOwn(operation, "active")) {
|
|
27551
27685
|
throw new Error(`${kind2} revise operation no longer supports 'active' — use retract('${name}') instead`);
|
|
27552
27686
|
}
|
|
27687
|
+
if (kind2 === "collection") {
|
|
27688
|
+
return normalizeBackendCollectionRevise(operation, "commit.apply");
|
|
27689
|
+
}
|
|
27553
27690
|
if (operation.data === undefined) {
|
|
27554
27691
|
throw new Error(`${kind2} revise operation requires 'data'`);
|
|
27555
27692
|
}
|
|
27556
|
-
if (kind2 === "collection") {
|
|
27557
|
-
throw new Error(`collection revise is no longer supported — use retract('${name}') instead`);
|
|
27558
|
-
}
|
|
27559
27693
|
if (kind2 === "assertion") {
|
|
27560
27694
|
return {
|
|
27561
27695
|
operation: "revise",
|
|
@@ -27590,6 +27724,9 @@ function toBackendStreamOperation(operation) {
|
|
|
27590
27724
|
if (!("about" in operation) || operation.about === undefined) {
|
|
27591
27725
|
throw new Error("assertion add operation requires 'about'");
|
|
27592
27726
|
}
|
|
27727
|
+
if (typeof operation.about !== "string") {
|
|
27728
|
+
throw new Error(COLLECTION_ABOUT_REMOVED_MESSAGE);
|
|
27729
|
+
}
|
|
27593
27730
|
if (operation.data === undefined) {
|
|
27594
27731
|
throw new Error("assertion add operation requires 'data'");
|
|
27595
27732
|
}
|
|
@@ -27782,34 +27919,14 @@ function computeBackoffDelayMs(attempt, policy) {
|
|
|
27782
27919
|
function sleep2(ms) {
|
|
27783
27920
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
27784
27921
|
}
|
|
27785
|
-
var TOKEN_REF_REGEX = /[$#]\d+/;
|
|
27786
|
-
function stringHasTokenRef(value) {
|
|
27787
|
-
return typeof value === "string" && TOKEN_REF_REGEX.test(value);
|
|
27788
|
-
}
|
|
27789
|
-
function structuralValueHasTokenRef(value, seen = new WeakSet) {
|
|
27790
|
-
if (stringHasTokenRef(value))
|
|
27791
|
-
return true;
|
|
27792
|
-
if (value !== null && typeof value === "object") {
|
|
27793
|
-
if (seen.has(value))
|
|
27794
|
-
return false;
|
|
27795
|
-
seen.add(value);
|
|
27796
|
-
if (Array.isArray(value)) {
|
|
27797
|
-
return value.some((entry) => structuralValueHasTokenRef(entry, seen));
|
|
27798
|
-
}
|
|
27799
|
-
return Object.values(value).some((entry) => structuralValueHasTokenRef(entry, seen));
|
|
27800
|
-
}
|
|
27801
|
-
return false;
|
|
27802
|
-
}
|
|
27803
|
-
function opUsesTokens(op) {
|
|
27804
|
-
return stringHasTokenRef(op.name) || stringHasTokenRef(op.wref) || structuralValueHasTokenRef(op.about) || stringHasTokenRef(op.aboutWref) || structuralValueHasTokenRef(op.members) || structuralValueHasTokenRef(op.data);
|
|
27805
|
-
}
|
|
27806
27922
|
|
|
27807
27923
|
// ../../packages/sdk-ts/src/stream-submit-submit.ts
|
|
27808
27924
|
class StreamValidationError extends Error {
|
|
27809
|
-
code
|
|
27925
|
+
code;
|
|
27810
27926
|
status = 400;
|
|
27811
|
-
constructor(message) {
|
|
27927
|
+
constructor(message, code = "VALIDATION_ERROR") {
|
|
27812
27928
|
super(message);
|
|
27929
|
+
this.code = code;
|
|
27813
27930
|
this.name = "WarmHubError";
|
|
27814
27931
|
}
|
|
27815
27932
|
}
|
|
@@ -27830,6 +27947,7 @@ async function submitOperationsViaStream(client, args) {
|
|
|
27830
27947
|
}
|
|
27831
27948
|
return streamOperation;
|
|
27832
27949
|
});
|
|
27950
|
+
validateNormalizedOperations(operations);
|
|
27833
27951
|
const chunkSize = normalizeChunkSize(args.chunkSize);
|
|
27834
27952
|
let streamId = args.streamId ?? createStreamId();
|
|
27835
27953
|
const policy = args.streamId !== undefined ? false : resolveRetryPolicy(args.retry);
|
|
@@ -27841,7 +27959,6 @@ async function submitOperationsViaStream(client, args) {
|
|
|
27841
27959
|
let attempt = 1;
|
|
27842
27960
|
let priorAttemptAmbiguous = false;
|
|
27843
27961
|
const chunkIsAtomic = chunk.length === 1;
|
|
27844
|
-
const chunkUsesTokens = chunk.some(opUsesTokens);
|
|
27845
27962
|
while (true) {
|
|
27846
27963
|
try {
|
|
27847
27964
|
const appendResult = await client.stream.append({
|
|
@@ -27864,7 +27981,7 @@ async function submitOperationsViaStream(client, args) {
|
|
|
27864
27981
|
if (chunkResults.length === 0 && !priorAttemptAmbiguous && isDefiniteClientError(cause)) {
|
|
27865
27982
|
throw cause;
|
|
27866
27983
|
}
|
|
27867
|
-
if (chunkResults.length === 0 && chunkIsAtomic &&
|
|
27984
|
+
if (chunkResults.length === 0 && chunkIsAtomic && policy !== false && attempt < policy.maxAttempts && isTransientStreamFailure(cause)) {
|
|
27868
27985
|
await sleep2(computeBackoffDelayMs(attempt, policy));
|
|
27869
27986
|
attempt += 1;
|
|
27870
27987
|
priorAttemptAmbiguous = true;
|
|
@@ -27898,6 +28015,16 @@ async function submitOperationsViaStream(client, args) {
|
|
|
27898
28015
|
}
|
|
27899
28016
|
return result;
|
|
27900
28017
|
}
|
|
28018
|
+
function validateNormalizedOperations(operations) {
|
|
28019
|
+
const diagnostics = preflightCommitDiagnostics2(operations).filter((diagnostic) => !isServerAuthoritativeSequenceDiagnostic(diagnostic));
|
|
28020
|
+
const firstDiagnostic = diagnostics[0];
|
|
28021
|
+
if (!firstDiagnostic)
|
|
28022
|
+
return;
|
|
28023
|
+
throw new StreamValidationError(`Invalid operation at index ${firstDiagnostic.operationIndex}: ${firstDiagnostic.message}`, firstDiagnostic.code);
|
|
28024
|
+
}
|
|
28025
|
+
function isServerAuthoritativeSequenceDiagnostic(diagnostic) {
|
|
28026
|
+
return diagnostic.code === "ILLEGAL_OP_SEQUENCE" && diagnostic.message.includes("Cannot revise then add ");
|
|
28027
|
+
}
|
|
27901
28028
|
function isAllSubmittedOperationsFailed(result, submittedOperationCount) {
|
|
27902
28029
|
if (submittedOperationCount <= 0) {
|
|
27903
28030
|
return false;
|
|
@@ -28098,6 +28225,35 @@ function sanitizeSubscriptionUpdateInput(input) {
|
|
|
28098
28225
|
} = input;
|
|
28099
28226
|
return supported;
|
|
28100
28227
|
}
|
|
28228
|
+
function hasCollectionQuerySource(source) {
|
|
28229
|
+
return !!source && (!!source.shape || !!source.kind || !!source.about || !!source.match || !!source.componentRef || source.excludeComponents === true || (source.where?.length ?? 0) > 0);
|
|
28230
|
+
}
|
|
28231
|
+
function hasCollectionSelectorAnchor(source) {
|
|
28232
|
+
return !!source && (!!source.shape || !!source.about || !!source.match || !!source.componentRef || (source.where?.length ?? 0) > 0);
|
|
28233
|
+
}
|
|
28234
|
+
function hasExplicitCollectionMembers(opts) {
|
|
28235
|
+
const members = opts.members;
|
|
28236
|
+
return Array.isArray(members) && members.length > 0;
|
|
28237
|
+
}
|
|
28238
|
+
function collectionTypeFromWref(wref) {
|
|
28239
|
+
const local = wref.replace(/^wh:[^/]+\/[^/]+\//, "").replace(/@(?:HEAD|ALL|v\d+)$/, "");
|
|
28240
|
+
const shape = local.split("/")[0]?.toLowerCase();
|
|
28241
|
+
return shape === "pair" || shape === "set" || shape === "list" ? shape : undefined;
|
|
28242
|
+
}
|
|
28243
|
+
function assertSelectorBackedCollectionType(type, opts) {
|
|
28244
|
+
if (hasCollectionQuerySource(opts.query) && !hasCollectionSelectorAnchor(opts.query)) {
|
|
28245
|
+
throw new WarmHubError("VALIDATION_ERROR", "Selector-backed collection sources require shape, about, match, componentRef, or where; kind and excludeComponents only narrow an existing selector.");
|
|
28246
|
+
}
|
|
28247
|
+
if (opts.sourceRepo && !hasCollectionSelectorAnchor(opts.query)) {
|
|
28248
|
+
throw new WarmHubError("VALIDATION_ERROR", "sourceRepo requires a selector-backed collection query");
|
|
28249
|
+
}
|
|
28250
|
+
if (opts.sourceRepo && hasExplicitCollectionMembers(opts)) {
|
|
28251
|
+
throw new WarmHubError("VALIDATION_ERROR", "sourceRepo cannot be combined with explicit members; use canonical wh:org/repo/... member wrefs or omit sourceRepo.");
|
|
28252
|
+
}
|
|
28253
|
+
if (hasCollectionQuerySource(opts.query) && type !== "set") {
|
|
28254
|
+
throw new WarmHubError("VALIDATION_ERROR", "Selector-backed collection sources are only supported for set collections");
|
|
28255
|
+
}
|
|
28256
|
+
}
|
|
28101
28257
|
function trpcClientCodeToWarmHubCode(code) {
|
|
28102
28258
|
switch (code) {
|
|
28103
28259
|
case "BAD_REQUEST":
|
|
@@ -29319,93 +29475,232 @@ class WarmHubClient {
|
|
|
29319
29475
|
}
|
|
29320
29476
|
}
|
|
29321
29477
|
};
|
|
29322
|
-
|
|
29323
|
-
|
|
29478
|
+
collection = {
|
|
29479
|
+
create: async (orgName, repoName, opts) => {
|
|
29324
29480
|
try {
|
|
29325
|
-
|
|
29326
|
-
return await this.trpc.
|
|
29481
|
+
assertSelectorBackedCollectionType(opts.type, opts);
|
|
29482
|
+
return await this.trpc.collection.create.mutate({
|
|
29327
29483
|
orgName,
|
|
29328
29484
|
repoName,
|
|
29329
|
-
|
|
29330
|
-
|
|
29331
|
-
|
|
29332
|
-
|
|
29333
|
-
|
|
29485
|
+
type: opts.type,
|
|
29486
|
+
name: opts.name,
|
|
29487
|
+
members: opts.members,
|
|
29488
|
+
from: opts.from,
|
|
29489
|
+
add: opts.add,
|
|
29490
|
+
remove: opts.remove,
|
|
29491
|
+
replaceMembers: opts.replaceMembers,
|
|
29492
|
+
query: opts.query,
|
|
29493
|
+
sourceOrgName: opts.sourceRepo?.orgName,
|
|
29494
|
+
sourceRepoName: opts.sourceRepo?.repoName,
|
|
29495
|
+
skipExisting: opts.skipExisting,
|
|
29496
|
+
message: opts.message,
|
|
29497
|
+
committer: opts.committer
|
|
29498
|
+
});
|
|
29499
|
+
} catch (error) {
|
|
29500
|
+
throw toWarmHubError(error);
|
|
29501
|
+
}
|
|
29502
|
+
},
|
|
29503
|
+
members: async (orgName, repoName, wref, opts) => {
|
|
29504
|
+
try {
|
|
29505
|
+
return await this.trpc.collection.members.query({
|
|
29506
|
+
orgName,
|
|
29507
|
+
repoName,
|
|
29508
|
+
wref,
|
|
29509
|
+
version: opts?.version,
|
|
29334
29510
|
limit: opts?.limit,
|
|
29335
|
-
cursor: opts?.cursor
|
|
29336
|
-
componentRef: opts?.componentRef,
|
|
29337
|
-
excludeComponents: opts?.excludeComponents,
|
|
29338
|
-
excludeInfraShapes: opts?.excludeInfraShapes,
|
|
29339
|
-
where: opts?.where
|
|
29511
|
+
cursor: opts?.cursor
|
|
29340
29512
|
});
|
|
29341
29513
|
} catch (error) {
|
|
29342
29514
|
throw toWarmHubError(error);
|
|
29343
29515
|
}
|
|
29344
29516
|
},
|
|
29345
|
-
|
|
29346
|
-
|
|
29517
|
+
membersIter: (orgName, repoName, wref, opts) => {
|
|
29518
|
+
let snapshotVersion = opts?.version;
|
|
29519
|
+
return paginate(async (cursor) => {
|
|
29520
|
+
const page = await this.collection.members(orgName, repoName, wref, {
|
|
29521
|
+
...opts,
|
|
29522
|
+
version: snapshotVersion,
|
|
29523
|
+
cursor
|
|
29524
|
+
});
|
|
29525
|
+
snapshotVersion ??= page.version;
|
|
29526
|
+
return page;
|
|
29527
|
+
}, (page) => page.items, opts?.cursor);
|
|
29347
29528
|
},
|
|
29348
|
-
|
|
29529
|
+
membersAll: async (orgName, repoName, wref, opts) => {
|
|
29349
29530
|
const { max, ...pageOpts } = opts ?? {};
|
|
29350
|
-
|
|
29531
|
+
let snapshotVersion = pageOpts.version;
|
|
29532
|
+
return await collectPaginatedPages(async (cursor) => {
|
|
29533
|
+
const page = await this.collection.members(orgName, repoName, wref, {
|
|
29534
|
+
...pageOpts,
|
|
29535
|
+
version: snapshotVersion,
|
|
29536
|
+
cursor
|
|
29537
|
+
});
|
|
29538
|
+
snapshotVersion ??= page.version;
|
|
29539
|
+
return page;
|
|
29540
|
+
}, (page) => page.items, max, pageOpts.cursor);
|
|
29351
29541
|
},
|
|
29352
|
-
|
|
29542
|
+
contains: async (orgName, repoName, wref, members, opts) => {
|
|
29353
29543
|
try {
|
|
29354
|
-
return await this.trpc.
|
|
29544
|
+
return await this.trpc.collection.contains.query({
|
|
29355
29545
|
orgName,
|
|
29356
29546
|
repoName,
|
|
29357
29547
|
wref,
|
|
29358
|
-
version,
|
|
29359
|
-
|
|
29548
|
+
version: opts?.version,
|
|
29549
|
+
members,
|
|
29550
|
+
position: opts?.position
|
|
29360
29551
|
});
|
|
29361
29552
|
} catch (error) {
|
|
29362
29553
|
throw toWarmHubError(error);
|
|
29363
29554
|
}
|
|
29364
29555
|
},
|
|
29365
|
-
|
|
29556
|
+
diff: async (orgName, repoName, leftWref, rightWref, opts) => {
|
|
29366
29557
|
try {
|
|
29367
|
-
return await this.trpc.
|
|
29558
|
+
return await this.trpc.collection.diff.query({
|
|
29368
29559
|
orgName,
|
|
29369
29560
|
repoName,
|
|
29370
|
-
|
|
29371
|
-
|
|
29561
|
+
leftWref,
|
|
29562
|
+
rightWref,
|
|
29563
|
+
leftVersion: opts?.leftVersion,
|
|
29564
|
+
rightVersion: opts?.rightVersion,
|
|
29565
|
+
mode: opts?.mode
|
|
29372
29566
|
});
|
|
29373
29567
|
} catch (error) {
|
|
29374
29568
|
throw toWarmHubError(error);
|
|
29375
29569
|
}
|
|
29376
29570
|
},
|
|
29377
|
-
|
|
29571
|
+
revise: async (orgName, repoName, wref, opts) => {
|
|
29378
29572
|
try {
|
|
29379
|
-
|
|
29573
|
+
const targetType = collectionTypeFromWref(wref);
|
|
29574
|
+
if (hasCollectionQuerySource(opts.query) && !hasCollectionSelectorAnchor(opts.query)) {
|
|
29575
|
+
throw new WarmHubError("VALIDATION_ERROR", "Selector-backed collection sources require shape, about, match, componentRef, or where; kind and excludeComponents only narrow an existing selector.");
|
|
29576
|
+
}
|
|
29577
|
+
if (opts.sourceRepo && !hasCollectionSelectorAnchor(opts.query)) {
|
|
29578
|
+
throw new WarmHubError("VALIDATION_ERROR", "sourceRepo requires a selector-backed collection query");
|
|
29579
|
+
}
|
|
29580
|
+
if (opts.sourceRepo && hasExplicitCollectionMembers(opts)) {
|
|
29581
|
+
throw new WarmHubError("VALIDATION_ERROR", "sourceRepo cannot be combined with explicit members; use canonical wh:org/repo/... member wrefs or omit sourceRepo.");
|
|
29582
|
+
}
|
|
29583
|
+
if (hasCollectionQuerySource(opts.query) && targetType && targetType !== "set") {
|
|
29584
|
+
throw new WarmHubError("VALIDATION_ERROR", "Selector-backed revise requires a Set/<name> target wref");
|
|
29585
|
+
}
|
|
29586
|
+
return await this.trpc.collection.revise.mutate({
|
|
29380
29587
|
orgName,
|
|
29381
29588
|
repoName,
|
|
29382
29589
|
wref,
|
|
29383
|
-
|
|
29590
|
+
members: opts.members,
|
|
29591
|
+
add: opts.add,
|
|
29592
|
+
remove: opts.remove,
|
|
29593
|
+
query: opts.query,
|
|
29594
|
+
sourceOrgName: opts.sourceRepo?.orgName,
|
|
29595
|
+
sourceRepoName: opts.sourceRepo?.repoName,
|
|
29596
|
+
message: opts.message,
|
|
29597
|
+
committer: opts.committer
|
|
29384
29598
|
});
|
|
29385
29599
|
} catch (error) {
|
|
29386
29600
|
throw toWarmHubError(error);
|
|
29387
29601
|
}
|
|
29388
29602
|
},
|
|
29389
|
-
|
|
29603
|
+
stats: async (orgName, repoName, wref, opts) => {
|
|
29390
29604
|
try {
|
|
29391
|
-
return await this.trpc.
|
|
29605
|
+
return await this.trpc.collection.stats.query({
|
|
29392
29606
|
orgName,
|
|
29393
29607
|
repoName,
|
|
29394
29608
|
wref,
|
|
29395
|
-
version: opts?.version
|
|
29396
|
-
depth: opts?.depth,
|
|
29397
|
-
limit: opts?.limit
|
|
29609
|
+
version: opts?.version
|
|
29398
29610
|
});
|
|
29399
29611
|
} catch (error) {
|
|
29400
29612
|
throw toWarmHubError(error);
|
|
29401
29613
|
}
|
|
29402
|
-
}
|
|
29403
|
-
|
|
29614
|
+
}
|
|
29615
|
+
};
|
|
29616
|
+
thing = {
|
|
29617
|
+
head: async (orgName, repoName, opts) => {
|
|
29404
29618
|
try {
|
|
29405
|
-
|
|
29406
|
-
|
|
29407
|
-
|
|
29408
|
-
|
|
29619
|
+
const kind = opts?.kind === "shape" || opts?.kind === "thing" || opts?.kind === "assertion" || opts?.kind === "collection" ? opts.kind : undefined;
|
|
29620
|
+
return await this.trpc.thing.head.query({
|
|
29621
|
+
orgName,
|
|
29622
|
+
repoName,
|
|
29623
|
+
shape: opts?.shape,
|
|
29624
|
+
kind,
|
|
29625
|
+
match: opts?.match,
|
|
29626
|
+
dataMode: opts?.dataMode,
|
|
29627
|
+
includeRetracted: opts?.includeRetracted,
|
|
29628
|
+
limit: opts?.limit,
|
|
29629
|
+
cursor: opts?.cursor,
|
|
29630
|
+
componentRef: opts?.componentRef,
|
|
29631
|
+
excludeComponents: opts?.excludeComponents,
|
|
29632
|
+
excludeInfraShapes: opts?.excludeInfraShapes,
|
|
29633
|
+
where: opts?.where
|
|
29634
|
+
});
|
|
29635
|
+
} catch (error) {
|
|
29636
|
+
throw toWarmHubError(error);
|
|
29637
|
+
}
|
|
29638
|
+
},
|
|
29639
|
+
headIter: (orgName, repoName, opts) => {
|
|
29640
|
+
return paginate((cursor) => this.thing.head(orgName, repoName, { ...opts, cursor }), (page) => page.items, opts?.cursor);
|
|
29641
|
+
},
|
|
29642
|
+
headAll: async (orgName, repoName, opts) => {
|
|
29643
|
+
const { max, ...pageOpts } = opts ?? {};
|
|
29644
|
+
return await collectPaginatedPages((cursor) => this.thing.head(orgName, repoName, { ...pageOpts, cursor }), (page) => page.items, max, pageOpts.cursor);
|
|
29645
|
+
},
|
|
29646
|
+
get: async (orgName, repoName, wref, version, opts) => {
|
|
29647
|
+
try {
|
|
29648
|
+
return await this.trpc.thing.get.query({
|
|
29649
|
+
orgName,
|
|
29650
|
+
repoName,
|
|
29651
|
+
wref,
|
|
29652
|
+
version,
|
|
29653
|
+
includeRetracted: opts?.includeRetracted,
|
|
29654
|
+
dataMode: opts?.dataMode
|
|
29655
|
+
});
|
|
29656
|
+
} catch (error) {
|
|
29657
|
+
throw toWarmHubError(error);
|
|
29658
|
+
}
|
|
29659
|
+
},
|
|
29660
|
+
getWithLease: async (orgName, repoName, wref, opts) => {
|
|
29661
|
+
try {
|
|
29662
|
+
return await this.trpc.thing.getWithLease.mutate({
|
|
29663
|
+
orgName,
|
|
29664
|
+
repoName,
|
|
29665
|
+
wref,
|
|
29666
|
+
ttlMs: opts?.ttlMs
|
|
29667
|
+
});
|
|
29668
|
+
} catch (error) {
|
|
29669
|
+
throw toWarmHubError(error);
|
|
29670
|
+
}
|
|
29671
|
+
},
|
|
29672
|
+
releaseLease: async (orgName, repoName, wref, leaseId) => {
|
|
29673
|
+
try {
|
|
29674
|
+
await this.trpc.thing.releaseLease.mutate({
|
|
29675
|
+
orgName,
|
|
29676
|
+
repoName,
|
|
29677
|
+
wref,
|
|
29678
|
+
leaseId
|
|
29679
|
+
});
|
|
29680
|
+
} catch (error) {
|
|
29681
|
+
throw toWarmHubError(error);
|
|
29682
|
+
}
|
|
29683
|
+
},
|
|
29684
|
+
graph: async (orgName, repoName, wref, opts) => {
|
|
29685
|
+
try {
|
|
29686
|
+
return await this.trpc.thing.graph.query({
|
|
29687
|
+
orgName,
|
|
29688
|
+
repoName,
|
|
29689
|
+
wref,
|
|
29690
|
+
version: opts?.version,
|
|
29691
|
+
depth: opts?.depth,
|
|
29692
|
+
limit: opts?.limit
|
|
29693
|
+
});
|
|
29694
|
+
} catch (error) {
|
|
29695
|
+
throw toWarmHubError(error);
|
|
29696
|
+
}
|
|
29697
|
+
},
|
|
29698
|
+
getMany: async (orgName, repoName, wrefs, version, opts) => {
|
|
29699
|
+
try {
|
|
29700
|
+
if (wrefs.length === 0) {
|
|
29701
|
+
return {
|
|
29702
|
+
requested: 0,
|
|
29703
|
+
items: [],
|
|
29409
29704
|
missing: []
|
|
29410
29705
|
};
|
|
29411
29706
|
}
|
|
@@ -29417,7 +29712,8 @@ class WarmHubClient {
|
|
|
29417
29712
|
repoName,
|
|
29418
29713
|
wrefs: chunkWrefs,
|
|
29419
29714
|
version,
|
|
29420
|
-
includeRetracted: opts?.includeRetracted
|
|
29715
|
+
includeRetracted: opts?.includeRetracted,
|
|
29716
|
+
dataMode: opts?.dataMode
|
|
29421
29717
|
});
|
|
29422
29718
|
};
|
|
29423
29719
|
if (wrefs.length <= chunkSize) {
|
|
@@ -32882,7 +33178,7 @@ function emitPartialPageHint(ctx, count, _nextCursor, _limit) {
|
|
|
32882
33178
|
}
|
|
32883
33179
|
|
|
32884
33180
|
// ../../packages/warmhub-cli/src/domains/assertion/shared.ts
|
|
32885
|
-
var COLLECTION_TAGS = ["pair", "
|
|
33181
|
+
var COLLECTION_TAGS = ["pair", "set", "list"];
|
|
32886
33182
|
function parseAbout(raw) {
|
|
32887
33183
|
const colonIdx = raw.indexOf(":");
|
|
32888
33184
|
if (colonIdx === -1) {
|
|
@@ -32892,32 +33188,7 @@ function parseAbout(raw) {
|
|
|
32892
33188
|
if (!COLLECTION_TAGS.includes(tag)) {
|
|
32893
33189
|
return raw;
|
|
32894
33190
|
}
|
|
32895
|
-
|
|
32896
|
-
const members = membersStr.split(",").map((m) => m.trim()).filter(Boolean);
|
|
32897
|
-
switch (tag) {
|
|
32898
|
-
case "pair":
|
|
32899
|
-
if (members.length !== 2) {
|
|
32900
|
-
throw new CliError(2 /* UserInput */, "USER_INPUT", `pair requires exactly 2 members, got ${members.length}`, undefined, "Example: --about pair:Location/a,Location/b");
|
|
32901
|
-
}
|
|
32902
|
-
return { pair: members };
|
|
32903
|
-
case "triple":
|
|
32904
|
-
if (members.length !== 3) {
|
|
32905
|
-
throw new CliError(2 /* UserInput */, "USER_INPUT", `triple requires exactly 3 members, got ${members.length}`, undefined, "Example: --about triple:Location/a,Location/b,Location/c");
|
|
32906
|
-
}
|
|
32907
|
-
return { triple: members };
|
|
32908
|
-
case "set":
|
|
32909
|
-
if (members.length === 0) {
|
|
32910
|
-
throw new CliError(2 /* UserInput */, "USER_INPUT", "set requires at least 1 member", undefined, "Example: --about set:Location/a,Location/b");
|
|
32911
|
-
}
|
|
32912
|
-
return { set: members };
|
|
32913
|
-
case "list":
|
|
32914
|
-
if (members.length === 0) {
|
|
32915
|
-
throw new CliError(2 /* UserInput */, "USER_INPUT", "list requires at least 1 member", undefined, "Example: --about list:Location/a,Location/b");
|
|
32916
|
-
}
|
|
32917
|
-
return { list: members };
|
|
32918
|
-
default:
|
|
32919
|
-
return raw;
|
|
32920
|
-
}
|
|
33191
|
+
throw new CliError(2 /* UserInput */, "USER_INPUT", COLLECTION_ABOUT_REMOVED_MESSAGE, undefined, "Use wh commit submit --file with a named collection add followed by an assertion add.");
|
|
32921
33192
|
}
|
|
32922
33193
|
function renderAbout(out, c, result) {
|
|
32923
33194
|
const target = result.target;
|
|
@@ -33015,24 +33286,24 @@ var createFlags = {
|
|
|
33015
33286
|
name: flag.string({ description: "Assertion name" }),
|
|
33016
33287
|
shape: flag.string({ description: "Shape for assertion (required)" }),
|
|
33017
33288
|
data: flag.string({ description: "Data payload (JSON)" }),
|
|
33018
|
-
about: flag.string({ description: "Target wref
|
|
33289
|
+
about: flag.string({ description: "Target wref" }),
|
|
33019
33290
|
message: flag.string({ short: "m", description: "Commit message" }),
|
|
33020
33291
|
committer: flag.string({
|
|
33021
|
-
description: "Committer
|
|
33292
|
+
description: "Committer wref (shape or shaped thing; e.g. Agent/bot-1)"
|
|
33022
33293
|
})
|
|
33023
33294
|
};
|
|
33024
33295
|
var reviseFlags = {
|
|
33025
33296
|
data: flag.string({ description: "Data payload (JSON)" }),
|
|
33026
33297
|
message: flag.string({ short: "m", description: "Commit message" }),
|
|
33027
33298
|
committer: flag.string({
|
|
33028
|
-
description: "Committer
|
|
33299
|
+
description: "Committer wref (shape or shaped thing; e.g. Agent/bot-1)"
|
|
33029
33300
|
})
|
|
33030
33301
|
};
|
|
33031
33302
|
var retractFlags = {
|
|
33032
33303
|
reason: flag.string({ description: "Reason for retraction (<=500 chars)" }),
|
|
33033
33304
|
message: flag.string({ short: "m", description: "Commit message" }),
|
|
33034
33305
|
committer: flag.string({
|
|
33035
|
-
description: "Committer
|
|
33306
|
+
description: "Committer wref (shape or shaped thing; e.g. Agent/bot-1)"
|
|
33036
33307
|
})
|
|
33037
33308
|
};
|
|
33038
33309
|
var handleRevise = async (ctx, { flags, args }) => {
|
|
@@ -33119,9 +33390,14 @@ var handleCreate = async (ctx, { flags, args }) => {
|
|
|
33119
33390
|
|
|
33120
33391
|
// ../../packages/warmhub-cli/src/domains/thing/shared.ts
|
|
33121
33392
|
var DURABLE_ID_PATTERN_RE = /^[0-9a-zA-HJ-NP-Tv-z]{60}(@(v\d+|HEAD|ALL))?$/i;
|
|
33393
|
+
var WREF_SEGMENT = String.raw`[^/?#@:\s$]+`;
|
|
33394
|
+
var CANONICAL_WREF_PATTERN_RE = new RegExp(String.raw`^wh:${WREF_SEGMENT}/${WREF_SEGMENT}/${WREF_SEGMENT}(?:/${WREF_SEGMENT})*(?:@(?:v[1-9]\d*|HEAD|ALL))?$`, "i");
|
|
33122
33395
|
function looksLikeDurableId(wref) {
|
|
33123
33396
|
return DURABLE_ID_PATTERN_RE.test(wref);
|
|
33124
33397
|
}
|
|
33398
|
+
function looksLikeCanonicalWref(wref) {
|
|
33399
|
+
return CANONICAL_WREF_PATTERN_RE.test(wref);
|
|
33400
|
+
}
|
|
33125
33401
|
var DEFAULT_PAGE_LIMIT = 50;
|
|
33126
33402
|
var DEFAULT_SEARCH_LIMIT = 25;
|
|
33127
33403
|
var MAX_PAGE_LIMIT = 500;
|
|
@@ -33273,7 +33549,7 @@ var createFlags2 = {
|
|
|
33273
33549
|
}),
|
|
33274
33550
|
message: flag.string({ short: "m", description: "Commit message" }),
|
|
33275
33551
|
committer: flag.string({
|
|
33276
|
-
description: "Committer
|
|
33552
|
+
description: "Committer wref (shape or shaped thing; e.g. Agent/bot-1)"
|
|
33277
33553
|
})
|
|
33278
33554
|
};
|
|
33279
33555
|
var handleCreate2 = async (ctx, { flags, args }) => {
|
|
@@ -33374,6 +33650,9 @@ function renderThing(out, c, result) {
|
|
|
33374
33650
|
out(` ${c.dim}revisedOn:${c.reset} ${formatTime(meta.revisedOn, now)}`);
|
|
33375
33651
|
}
|
|
33376
33652
|
}
|
|
33653
|
+
if (result.collection) {
|
|
33654
|
+
renderCollectionSummary(out, c, result.collection);
|
|
33655
|
+
}
|
|
33377
33656
|
const fields = shapeName && result.data ? collectionFields(shapeName, result.data) : null;
|
|
33378
33657
|
if (fields) {
|
|
33379
33658
|
for (const field of fields) {
|
|
@@ -33396,6 +33675,21 @@ function renderThing(out, c, result) {
|
|
|
33396
33675
|
}
|
|
33397
33676
|
}
|
|
33398
33677
|
}
|
|
33678
|
+
function renderCollectionSummary(out, c, collection) {
|
|
33679
|
+
out(` ${c.dim}collection:${c.reset} ${collection.type}`);
|
|
33680
|
+
out(` ${c.dim}members:${c.reset} ${collection.memberCount}`);
|
|
33681
|
+
if (collection.fullData)
|
|
33682
|
+
return;
|
|
33683
|
+
const limit = collection.inlineLimit ? ` > ${collection.inlineLimit}` : " above inline limit";
|
|
33684
|
+
out(` ${c.dim}data:${c.reset} elided (${collection.memberCount}${limit}; use --data-mode full)`);
|
|
33685
|
+
const preview = collection.preview ?? [];
|
|
33686
|
+
if (preview.length === 0)
|
|
33687
|
+
return;
|
|
33688
|
+
out(` ${c.dim}preview:${c.reset}`);
|
|
33689
|
+
for (const wref of preview) {
|
|
33690
|
+
out(` ${pinnedWref(c, wref)}`);
|
|
33691
|
+
}
|
|
33692
|
+
}
|
|
33399
33693
|
function renderDataBlock(out, data, indent) {
|
|
33400
33694
|
const lines = JSON.stringify(data, null, 2).split(`
|
|
33401
33695
|
`);
|
|
@@ -33587,7 +33881,7 @@ var historyFlags = {
|
|
|
33587
33881
|
description: "Allow retracted shape/about targets to resolve"
|
|
33588
33882
|
}),
|
|
33589
33883
|
"resolve-collections": flag.boolean({
|
|
33590
|
-
description: "Include assertions about collections (Pair/
|
|
33884
|
+
description: "Include assertions about collections (Pair/Set/List) containing the target. Only applies with --about."
|
|
33591
33885
|
})
|
|
33592
33886
|
};
|
|
33593
33887
|
var handleHistory = async (ctx, { flags, args }) => {
|
|
@@ -33978,7 +34272,7 @@ var queryFlags = {
|
|
|
33978
34272
|
description: "Include retracted things"
|
|
33979
34273
|
}),
|
|
33980
34274
|
"resolve-collections": flag.boolean({
|
|
33981
|
-
description: "Include assertions about collections (Pair/
|
|
34275
|
+
description: "Include assertions about collections (Pair/Set/List) containing the target. Only applies with --about."
|
|
33982
34276
|
}),
|
|
33983
34277
|
component: flag.string({
|
|
33984
34278
|
description: "Filter to things owned by this component (Org/Name ref)"
|
|
@@ -34159,10 +34453,10 @@ function renderQueryResults(out, c, result) {
|
|
|
34159
34453
|
// ../../packages/warmhub-cli/src/domains/thing/refs.ts
|
|
34160
34454
|
var refsFlags = {
|
|
34161
34455
|
inbound: flag.boolean({
|
|
34162
|
-
description: "Show inbound refs (what references this
|
|
34456
|
+
description: "Show inbound refs (what references this target) [default]"
|
|
34163
34457
|
}),
|
|
34164
34458
|
outbound: flag.boolean({
|
|
34165
|
-
description: "Show outbound refs (what this
|
|
34459
|
+
description: "Show outbound refs (what this target references)"
|
|
34166
34460
|
}),
|
|
34167
34461
|
field: flag.string({ description: "Filter by field path (inbound only)" }),
|
|
34168
34462
|
limit: flag.number({
|
|
@@ -34277,7 +34571,7 @@ var handleResolve = async (ctx, { args }) => {
|
|
|
34277
34571
|
if (!wref) {
|
|
34278
34572
|
usageError("Usage: wh thing resolve <wref>", "wh thing resolve player");
|
|
34279
34573
|
}
|
|
34280
|
-
const { org, repo } = looksLikeDurableId(wref) ? parseOrgRepoOptional(getRepoRef(ctx), ctx.config) : parseOrgRepo(getRepoRef(ctx), ctx.config);
|
|
34574
|
+
const { org, repo } = looksLikeDurableId(wref) || looksLikeCanonicalWref(wref) ? parseOrgRepoOptional(getRepoRef(ctx), ctx.config) : parseOrgRepo(getRepoRef(ctx), ctx.config);
|
|
34281
34575
|
const c = ctx.colors;
|
|
34282
34576
|
const result = await ctx.client.thing.resolve(org, repo, wref);
|
|
34283
34577
|
writeOutput(ctx, result, () => {
|
|
@@ -34297,7 +34591,7 @@ var retractFlags2 = {
|
|
|
34297
34591
|
reason: flag.string({ description: "Reason for retraction (<=500 chars)" }),
|
|
34298
34592
|
message: flag.string({ short: "m", description: "Commit message" }),
|
|
34299
34593
|
committer: flag.string({
|
|
34300
|
-
description: "Committer
|
|
34594
|
+
description: "Committer wref (shape or shaped thing; e.g. Agent/bot-1)"
|
|
34301
34595
|
}),
|
|
34302
34596
|
"lease-id": flag.string({
|
|
34303
34597
|
description: "Read-lease token from `wh thing lease` (auto-released on success)"
|
|
@@ -34337,7 +34631,7 @@ var reviseFlags2 = {
|
|
|
34337
34631
|
data: flag.string({ description: "Data payload (JSON)" }),
|
|
34338
34632
|
message: flag.string({ short: "m", description: "Commit message" }),
|
|
34339
34633
|
committer: flag.string({
|
|
34340
|
-
description: "Committer
|
|
34634
|
+
description: "Committer wref (shape or shaped thing; e.g. Agent/bot-1)"
|
|
34341
34635
|
}),
|
|
34342
34636
|
"expected-version": flag.number({
|
|
34343
34637
|
description: "Only apply if the target is still at this version (optimistic concurrency)"
|
|
@@ -34391,7 +34685,7 @@ var searchFlags = {
|
|
|
34391
34685
|
description: "Include retracted things"
|
|
34392
34686
|
}),
|
|
34393
34687
|
"resolve-collections": flag.boolean({
|
|
34394
|
-
description: "Include assertions about collections (Pair/
|
|
34688
|
+
description: "Include assertions about collections (Pair/Set/List) containing the target. Only applies with --about."
|
|
34395
34689
|
}),
|
|
34396
34690
|
limit: flag.number({ description: "Max results (default: 25, max: 500)" }),
|
|
34397
34691
|
cursor: flag.string({ description: "Opaque pagination cursor (text mode)" }),
|
|
@@ -34550,10 +34844,13 @@ var viewFlags = {
|
|
|
34550
34844
|
description: "Resolve embedded graph to this depth (1-5)"
|
|
34551
34845
|
}),
|
|
34552
34846
|
"include-retracted": flag.boolean({
|
|
34553
|
-
description: "View a retracted thing"
|
|
34847
|
+
description: "View a retracted shape or shaped thing"
|
|
34554
34848
|
}),
|
|
34555
34849
|
file: flag.string({
|
|
34556
34850
|
description: "Read additional wrefs from <path>, one per line. Use `--file=-` for stdin (the `=` form is required) or pass bare `-` as a positional. Lines starting with '#' and blank lines are ignored; lines are not split on any other character."
|
|
34851
|
+
}),
|
|
34852
|
+
"data-mode": flag.string({
|
|
34853
|
+
description: "Collection data mode: auto (default) or full. Use full to force large collection bodies into thing view output."
|
|
34557
34854
|
})
|
|
34558
34855
|
};
|
|
34559
34856
|
var MAX_GET_MANY_WREFS = 500;
|
|
@@ -34568,6 +34865,13 @@ async function readStreamUtf8(input) {
|
|
|
34568
34865
|
function parseLineList(text) {
|
|
34569
34866
|
return text.split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#"));
|
|
34570
34867
|
}
|
|
34868
|
+
function validateDataMode(value) {
|
|
34869
|
+
if (value === undefined)
|
|
34870
|
+
return;
|
|
34871
|
+
if (value === "auto" || value === "full")
|
|
34872
|
+
return value;
|
|
34873
|
+
usageError("--data-mode must be auto or full", "wh thing view Set/wake-voters --data-mode full");
|
|
34874
|
+
}
|
|
34571
34875
|
async function collectWrefs(opts) {
|
|
34572
34876
|
const dashPositional = opts.positionals.includes("-");
|
|
34573
34877
|
const cleanPositionals = opts.positionals.filter((a) => a !== "-");
|
|
@@ -34606,12 +34910,16 @@ async function runSingleView(ctx, wref, flags) {
|
|
|
34606
34910
|
const depth = flags.depth;
|
|
34607
34911
|
const { org, repo } = looksLikeDurableId(wref) && depth === undefined ? parseOrgRepoOptional(getRepoRef(ctx), ctx.config) : parseOrgRepo(getRepoRef(ctx), ctx.config);
|
|
34608
34912
|
const includeRetracted = flags["include-retracted"] || version !== undefined;
|
|
34913
|
+
const dataMode = validateDataMode(flags["data-mode"]);
|
|
34609
34914
|
if (depth !== undefined && (depth < 1 || depth > 5)) {
|
|
34610
34915
|
usageError("Usage: wh thing view <wref> --depth <1-5>", "wh thing view Game/base --depth 2");
|
|
34611
34916
|
}
|
|
34612
34917
|
if (depth !== undefined && ctx.liveMode) {
|
|
34613
34918
|
usageError("--depth is not supported with --live", "wh thing view Game/base --depth 2");
|
|
34614
34919
|
}
|
|
34920
|
+
if (depth !== undefined && dataMode !== undefined) {
|
|
34921
|
+
usageError("--data-mode cannot be combined with --depth on `view` (graph reads use a separate payload shape).", "wh thing view Set/wake-voters --data-mode full");
|
|
34922
|
+
}
|
|
34615
34923
|
if (depth !== undefined && (flags["include-retracted"] || version !== undefined)) {
|
|
34616
34924
|
usageError("--depth cannot be combined with --include-retracted or --version on `view` (graph reads are active-only). Use `wh thing graph` for version-pinned graph reads.", "wh thing view Game/base --depth 2");
|
|
34617
34925
|
}
|
|
@@ -34619,7 +34927,8 @@ async function runSingleView(ctx, wref, flags) {
|
|
|
34619
34927
|
await runLive({
|
|
34620
34928
|
apiUrl: ctx.config.apiUrl,
|
|
34621
34929
|
poll: (c) => c.thing.get(org, repo, wref, version, {
|
|
34622
|
-
includeRetracted
|
|
34930
|
+
includeRetracted,
|
|
34931
|
+
dataMode
|
|
34623
34932
|
}),
|
|
34624
34933
|
render: (r) => renderThing(ctx.out, ctx.colors, r),
|
|
34625
34934
|
out: ctx.out,
|
|
@@ -34644,7 +34953,8 @@ async function runSingleView(ctx, wref, flags) {
|
|
|
34644
34953
|
return;
|
|
34645
34954
|
}
|
|
34646
34955
|
const result = await ctx.client.thing.get(org, repo, wref, version, {
|
|
34647
|
-
includeRetracted
|
|
34956
|
+
includeRetracted,
|
|
34957
|
+
dataMode
|
|
34648
34958
|
});
|
|
34649
34959
|
writeOutput(ctx, result, () => renderThing(ctx.out, ctx.colors, result));
|
|
34650
34960
|
}
|
|
@@ -34652,7 +34962,8 @@ async function runBatchView(ctx, wrefs, flags) {
|
|
|
34652
34962
|
const allDurable = wrefs.length > 0 && wrefs.every(looksLikeDurableId);
|
|
34653
34963
|
const { org, repo } = allDurable ? parseOrgRepoOptional(getRepoRef(ctx), ctx.config) : parseOrgRepo(getRepoRef(ctx), ctx.config);
|
|
34654
34964
|
const includeRetracted = flags["include-retracted"] || flags.version !== undefined;
|
|
34655
|
-
const
|
|
34965
|
+
const dataMode = validateDataMode(flags["data-mode"]);
|
|
34966
|
+
const result = await ctx.client.thing.getMany(org, repo, wrefs, flags.version, { includeRetracted, dataMode });
|
|
34656
34967
|
if (ctx.format === "jsonl") {
|
|
34657
34968
|
for (const event of walkBatchResult(wrefs, result, flags.version)) {
|
|
34658
34969
|
if (event.kind === "miss") {
|
|
@@ -34760,7 +35071,7 @@ var THING_DOMAIN = defineDomain({
|
|
|
34760
35071
|
},
|
|
34761
35072
|
resolve: {
|
|
34762
35073
|
prime: true,
|
|
34763
|
-
summary: "Resolve wref to thing",
|
|
35074
|
+
summary: "Resolve a wref to its canonical thing identity",
|
|
34764
35075
|
args: "<wref>",
|
|
34765
35076
|
handler: handleResolve
|
|
34766
35077
|
},
|
|
@@ -34784,7 +35095,7 @@ var THING_DOMAIN = defineDomain({
|
|
|
34784
35095
|
},
|
|
34785
35096
|
retract: {
|
|
34786
35097
|
prime: true,
|
|
34787
|
-
summary: "Withdraw a thing
|
|
35098
|
+
summary: "Withdraw a thing. Irreversible for the given identity.",
|
|
34788
35099
|
args: "<wref>",
|
|
34789
35100
|
flags: retractFlags2,
|
|
34790
35101
|
examples: [
|
|
@@ -34822,7 +35133,7 @@ var THING_DOMAIN = defineDomain({
|
|
|
34822
35133
|
},
|
|
34823
35134
|
refs: {
|
|
34824
35135
|
prime: true,
|
|
34825
|
-
summary: "Show refs (backlinks or cross-references) for a
|
|
35136
|
+
summary: "Show refs (backlinks or cross-references) for a target",
|
|
34826
35137
|
args: "<wref>",
|
|
34827
35138
|
flags: refsFlags,
|
|
34828
35139
|
examples: [
|
|
@@ -34854,7 +35165,7 @@ var THING_DOMAIN = defineDomain({
|
|
|
34854
35165
|
"wh thing graph Game/base --depth 2"
|
|
34855
35166
|
],
|
|
34856
35167
|
notes: [
|
|
34857
|
-
"`graph` does not traverse inbound wref-field references; use `wh thing refs <wref> --inbound` to find things whose fields point at this
|
|
35168
|
+
"`graph` does not traverse inbound wref-field references; use `wh thing refs <wref> --inbound` to find things whose fields point at this target."
|
|
34858
35169
|
],
|
|
34859
35170
|
handler: handleThingGraph
|
|
34860
35171
|
}
|
|
@@ -34879,9 +35190,9 @@ var handleView2 = async (ctx, { flags, args }) => {
|
|
|
34879
35190
|
if (!wref) {
|
|
34880
35191
|
usageError("Usage: wh assertion view <wref> [--version <n>] [--depth <n>]", "wh assertion view Belief/cave-safe --depth 2");
|
|
34881
35192
|
}
|
|
34882
|
-
const { org, repo } = parseOrgRepo(getRepoRef(ctx), ctx.config);
|
|
34883
35193
|
const version = flags.version;
|
|
34884
35194
|
const depth = flags.depth;
|
|
35195
|
+
const { org, repo } = looksLikeDurableId(wref) && depth === undefined ? parseOrgRepoOptional(getRepoRef(ctx), ctx.config) : parseOrgRepo(getRepoRef(ctx), ctx.config);
|
|
34885
35196
|
const includeRetracted = flags["include-retracted"] || version !== undefined;
|
|
34886
35197
|
if (depth !== undefined && (depth < 1 || depth > 5)) {
|
|
34887
35198
|
usageError("Usage: wh assertion view <wref> --depth <1-5>", "wh assertion view Belief/cave-safe --depth 2");
|
|
@@ -34943,7 +35254,7 @@ var handleHistory2 = async (ctx, { flags, args }) => {
|
|
|
34943
35254
|
if (ctx.liveMode && flags.all) {
|
|
34944
35255
|
usageError("Usage: wh assertion history <wref> [--limit N] [--cursor TOKEN] [--live]", "wh assertion history Belief/cave-safe --limit 50 --live");
|
|
34945
35256
|
}
|
|
34946
|
-
const { org, repo } = parseOrgRepo(getRepoRef(ctx), ctx.config);
|
|
35257
|
+
const { org, repo } = looksLikeDurableId(wref) ? parseOrgRepoOptional(getRepoRef(ctx), ctx.config) : parseOrgRepo(getRepoRef(ctx), ctx.config);
|
|
34947
35258
|
const limit = Math.min(flags.limit ?? DEFAULT_PAGE_LIMIT2, MAX_PAGE_LIMIT2);
|
|
34948
35259
|
if (ctx.liveMode) {
|
|
34949
35260
|
await runLive({
|
|
@@ -34995,7 +35306,9 @@ var handleHistory2 = async (ctx, { flags, args }) => {
|
|
|
34995
35306
|
writePageOutput(ctx, result.versions, { limit, nextCursor: result.nextCursor ?? null }, () => renderHistory(ctx.out, ctx.colors, result));
|
|
34996
35307
|
};
|
|
34997
35308
|
var listFlags = {
|
|
34998
|
-
about: flag.string({
|
|
35309
|
+
about: flag.string({
|
|
35310
|
+
description: "Target wref (thing or shape, required)"
|
|
35311
|
+
}),
|
|
34999
35312
|
shape: flag.string({ description: "Filter by shape" }),
|
|
35000
35313
|
depth: flag.number({ description: "Assertion depth" }),
|
|
35001
35314
|
limit: flag.number({
|
|
@@ -35006,7 +35319,7 @@ var listFlags = {
|
|
|
35006
35319
|
count: flag.boolean({ description: "Return count of matching assertions" }),
|
|
35007
35320
|
match: flag.string({ description: "Filter by wref glob pattern" }),
|
|
35008
35321
|
"resolve-collections": flag.boolean({
|
|
35009
|
-
description: "Include assertions about collections (Pair/
|
|
35322
|
+
description: "Include assertions about collections (Pair/Set/List) containing the target."
|
|
35010
35323
|
}),
|
|
35011
35324
|
"include-retracted": flag.boolean({
|
|
35012
35325
|
description: "Include retracted assertions"
|
|
@@ -35189,7 +35502,7 @@ var ASSERTION_DOMAIN = defineDomain({
|
|
|
35189
35502
|
flags: createFlags,
|
|
35190
35503
|
examples: [
|
|
35191
35504
|
`wh assertion create --shape belief --about player --data '{"confidence":0.8}'`,
|
|
35192
|
-
`wh assertion create --shape Distance --about
|
|
35505
|
+
`wh assertion create --shape Distance --about Pair/location-distance --data '{"value":5}'`
|
|
35193
35506
|
],
|
|
35194
35507
|
handler: handleCreate
|
|
35195
35508
|
},
|
|
@@ -36580,6 +36893,693 @@ var CHANNEL_DOMAIN = defineDomain({
|
|
|
36580
36893
|
handler: handleChannel
|
|
36581
36894
|
});
|
|
36582
36895
|
|
|
36896
|
+
// ../../packages/warmhub-cli/src/domains/collection-helpers.ts
|
|
36897
|
+
import { readFileSync as readFileSync6 } from "node:fs";
|
|
36898
|
+
function parseMemberList(values) {
|
|
36899
|
+
return (values ?? []).flatMap((value) => value.split(",")).map((value) => value.trim()).filter(Boolean);
|
|
36900
|
+
}
|
|
36901
|
+
async function readMembersFromSources(ctx, opts) {
|
|
36902
|
+
const field = opts.wrefField ?? "wref";
|
|
36903
|
+
const members = [
|
|
36904
|
+
...opts.positionals ?? [],
|
|
36905
|
+
...parseMemberList(opts.members)
|
|
36906
|
+
];
|
|
36907
|
+
const fileIsStdin = opts.file === "-";
|
|
36908
|
+
if ((opts.stdin || fileIsStdin) && isTTY(ctx.stdin ?? process.stdin)) {
|
|
36909
|
+
throw new CliError(2 /* UserInput */, "USER_INPUT", "Stdin requested but stdin is a terminal. Pipe input or remove the stdin flag.", undefined, "Example: wh collection create --type set --name audited --stdin");
|
|
36910
|
+
}
|
|
36911
|
+
if (opts.file && !fileIsStdin) {
|
|
36912
|
+
let raw;
|
|
36913
|
+
try {
|
|
36914
|
+
raw = readFileSync6(opts.file, "utf8");
|
|
36915
|
+
} catch (error) {
|
|
36916
|
+
const code = error.code;
|
|
36917
|
+
throw new CliError(2 /* UserInput */, "USER_INPUT", `Cannot read ${opts.file}${code ? ` (${code})` : ""}.`, error, "Check the path or use --file - to read collection members from stdin.");
|
|
36918
|
+
}
|
|
36919
|
+
members.push(...parseMembersPayload(raw, opts.label ?? "--file", field));
|
|
36920
|
+
}
|
|
36921
|
+
if (opts.stdin || fileIsStdin) {
|
|
36922
|
+
const raw = await readStreamUtf82(ctx.stdin ?? process.stdin);
|
|
36923
|
+
members.push(...parseMembersPayload(raw, opts.label ?? "stdin", field));
|
|
36924
|
+
}
|
|
36925
|
+
return members;
|
|
36926
|
+
}
|
|
36927
|
+
function hasCollectionQuerySource2(source) {
|
|
36928
|
+
return !!source.shape || !!source.kind || !!source.about || !!source.match || !!source.componentRef || source.excludeComponents === true || (source.where?.length ?? 0) > 0;
|
|
36929
|
+
}
|
|
36930
|
+
function hasCollectionSelectorAnchor2(source) {
|
|
36931
|
+
return !!source.shape || !!source.about || !!source.match || !!source.componentRef || (source.where?.length ?? 0) > 0;
|
|
36932
|
+
}
|
|
36933
|
+
function requireMembers(members, example) {
|
|
36934
|
+
if (members.length === 0) {
|
|
36935
|
+
usageError("At least one collection member is required", example);
|
|
36936
|
+
}
|
|
36937
|
+
}
|
|
36938
|
+
function renderMutation(ctx, result) {
|
|
36939
|
+
const c = ctx.colors;
|
|
36940
|
+
const action = result.status === "noop" ? "=" : "+";
|
|
36941
|
+
const color = result.status === "noop" ? c.dim : c.green;
|
|
36942
|
+
ctx.out(`${color}${action}${c.reset} ${displayName(c, result.wref)} ${c.dim}${result.type} ${result.memberCount} members${c.reset}`);
|
|
36943
|
+
}
|
|
36944
|
+
function renderMembers(ctx, result) {
|
|
36945
|
+
const c = ctx.colors;
|
|
36946
|
+
if (result.items.length === 0) {
|
|
36947
|
+
ctx.out(`${c.dim}No members${c.reset}`);
|
|
36948
|
+
return;
|
|
36949
|
+
}
|
|
36950
|
+
for (const item of result.items) {
|
|
36951
|
+
const position = item.position ?? 0;
|
|
36952
|
+
ctx.out(`${String(position).padStart(4, " ")} ${pinnedWref(c, item.wref)}`);
|
|
36953
|
+
}
|
|
36954
|
+
}
|
|
36955
|
+
function renderContains(ctx, result) {
|
|
36956
|
+
const c = ctx.colors;
|
|
36957
|
+
for (const item of result.results) {
|
|
36958
|
+
const marker = item.contains ? ctx.chars.check : ctx.chars.cross;
|
|
36959
|
+
const color = item.contains ? c.green : c.red;
|
|
36960
|
+
const at = item.positions === undefined || item.positions.length === 0 ? "" : ` ${c.dim}@${item.positions.join(",")}${c.reset}`;
|
|
36961
|
+
ctx.out(`${color}${marker}${c.reset} ${pinnedWref(c, item.member)}${at}`);
|
|
36962
|
+
}
|
|
36963
|
+
}
|
|
36964
|
+
function renderDiff(ctx, result) {
|
|
36965
|
+
const c = ctx.colors;
|
|
36966
|
+
if (result.mode === "ordered") {
|
|
36967
|
+
if (result.changed.length === 0) {
|
|
36968
|
+
ctx.out(`${c.dim}No ordered differences${c.reset}`);
|
|
36969
|
+
return;
|
|
36970
|
+
}
|
|
36971
|
+
for (const item of result.changed) {
|
|
36972
|
+
const left = item.left?.wref ?? `${c.dim}(none)${c.reset}`;
|
|
36973
|
+
const right = item.right?.wref ?? `${c.dim}(none)${c.reset}`;
|
|
36974
|
+
ctx.out(`${String(item.position).padStart(4, " ")} ${left} -> ${right}`);
|
|
36975
|
+
}
|
|
36976
|
+
return;
|
|
36977
|
+
}
|
|
36978
|
+
if (result.added.length === 0 && result.removed.length === 0) {
|
|
36979
|
+
ctx.out(`${c.dim}No membership differences${c.reset}`);
|
|
36980
|
+
return;
|
|
36981
|
+
}
|
|
36982
|
+
for (const member of result.added) {
|
|
36983
|
+
ctx.out(`${c.green}+${c.reset} ${member.wref}`);
|
|
36984
|
+
}
|
|
36985
|
+
for (const member of result.removed) {
|
|
36986
|
+
ctx.out(`${c.red}-${c.reset} ${member.wref}`);
|
|
36987
|
+
}
|
|
36988
|
+
}
|
|
36989
|
+
function renderStats(ctx, result) {
|
|
36990
|
+
const c = ctx.colors;
|
|
36991
|
+
ctx.out(`${pinnedWref(c, result.wref)} ${c.dim}${result.type}${c.reset}`);
|
|
36992
|
+
ctx.out(`members: ${result.memberCount}`);
|
|
36993
|
+
ctx.out(`unique: ${result.uniqueMemberCount}`);
|
|
36994
|
+
}
|
|
36995
|
+
function memberFromUnknown(value, field, label) {
|
|
36996
|
+
if (typeof value === "string" && value.trim().length > 0) {
|
|
36997
|
+
return value.trim();
|
|
36998
|
+
}
|
|
36999
|
+
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
37000
|
+
const raw = value[field];
|
|
37001
|
+
if (typeof raw === "string" && raw.trim().length > 0) {
|
|
37002
|
+
return raw.trim();
|
|
37003
|
+
}
|
|
37004
|
+
}
|
|
37005
|
+
throw new CliError(2 /* UserInput */, "USER_INPUT", `Invalid member entry in ${label}. Expected a string wref or an object with "${field}".`, undefined, `Use string wrefs or objects like {"${field}":"Shape/name"}.`);
|
|
37006
|
+
}
|
|
37007
|
+
function parseMembersPayload(raw, label, field = "wref") {
|
|
37008
|
+
const trimmed = raw.trim();
|
|
37009
|
+
if (!trimmed)
|
|
37010
|
+
return [];
|
|
37011
|
+
if (trimmed.startsWith("[")) {
|
|
37012
|
+
const parsed = safeParseJson(trimmed, label);
|
|
37013
|
+
if (!Array.isArray(parsed)) {
|
|
37014
|
+
throw new CliError(2 /* UserInput */, "USER_INPUT", `Invalid ${label}. Expected a JSON array.`, undefined, `Use a JSON array of string wrefs or objects with "${field}".`);
|
|
37015
|
+
}
|
|
37016
|
+
return parsed.map((entry) => memberFromUnknown(entry, field, label));
|
|
37017
|
+
}
|
|
37018
|
+
if (trimmed.startsWith("{")) {
|
|
37019
|
+
let objectParseError;
|
|
37020
|
+
try {
|
|
37021
|
+
const parsed = safeParseJson(trimmed, label);
|
|
37022
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed) && Array.isArray(parsed.members)) {
|
|
37023
|
+
return parsed.members.map((entry) => memberFromUnknown(entry, field, label));
|
|
37024
|
+
}
|
|
37025
|
+
return [memberFromUnknown(parsed, field, label)];
|
|
37026
|
+
} catch (error) {
|
|
37027
|
+
objectParseError = error;
|
|
37028
|
+
}
|
|
37029
|
+
const lines = trimmed.split(/\r?\n/).filter((line) => line.trim());
|
|
37030
|
+
if (lines.length > 1) {
|
|
37031
|
+
return lines.map((line) => memberFromUnknown(safeParseJson(line, label), field, label));
|
|
37032
|
+
}
|
|
37033
|
+
throw objectParseError;
|
|
37034
|
+
}
|
|
37035
|
+
return trimmed.split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#"));
|
|
37036
|
+
}
|
|
37037
|
+
async function readStreamUtf82(input) {
|
|
37038
|
+
let data = "";
|
|
37039
|
+
input.setEncoding?.("utf8");
|
|
37040
|
+
for await (const chunk of input) {
|
|
37041
|
+
data += typeof chunk === "string" ? chunk : chunk.toString("utf8");
|
|
37042
|
+
}
|
|
37043
|
+
return data;
|
|
37044
|
+
}
|
|
37045
|
+
|
|
37046
|
+
// ../../packages/warmhub-cli/src/domains/collection.ts
|
|
37047
|
+
var COLLECTION_TYPES = ["pair", "set", "list"];
|
|
37048
|
+
var commonWriteFlags = {
|
|
37049
|
+
message: flag.string({ short: "m", description: "Commit message" }),
|
|
37050
|
+
committer: flag.string({
|
|
37051
|
+
description: "Committer wref (shape or shaped thing; e.g. Agent/bot-1)"
|
|
37052
|
+
})
|
|
37053
|
+
};
|
|
37054
|
+
var collectionInputFlags = {
|
|
37055
|
+
members: flag.string({
|
|
37056
|
+
multiple: true,
|
|
37057
|
+
description: "Collection member wrefs. May be repeated; comma-separated values are also accepted."
|
|
37058
|
+
}),
|
|
37059
|
+
file: flag.string({
|
|
37060
|
+
description: "Read member wrefs from a file. Supports newline text, JSON array, JSON object with members, or JSONL. Use --file=- for stdin."
|
|
37061
|
+
}),
|
|
37062
|
+
stdin: flag.boolean({
|
|
37063
|
+
description: "Read member wrefs from stdin. Supports newline text, JSON array, JSON object with members, or JSONL."
|
|
37064
|
+
}),
|
|
37065
|
+
"wref-field": flag.string({
|
|
37066
|
+
description: "Object field to read when --file/--stdin contains JSON objects (default: wref)."
|
|
37067
|
+
})
|
|
37068
|
+
};
|
|
37069
|
+
var collectionQueryFlags = {
|
|
37070
|
+
shape: flag.string({ description: "Select set members by shape" }),
|
|
37071
|
+
kind: flag.string({ description: "Select set members by kind" }),
|
|
37072
|
+
about: flag.string({ description: "Select set members by about wref" }),
|
|
37073
|
+
match: flag.string({
|
|
37074
|
+
description: "Select set members by the same name pattern accepted by wh thing query --match"
|
|
37075
|
+
}),
|
|
37076
|
+
component: flag.string({
|
|
37077
|
+
description: "Select set members owned by this component (Org/Name ref)"
|
|
37078
|
+
}),
|
|
37079
|
+
"exclude-components": flag.boolean({
|
|
37080
|
+
description: "Exclude component-owned records from selector-backed sets"
|
|
37081
|
+
}),
|
|
37082
|
+
where: flag.string({
|
|
37083
|
+
multiple: true,
|
|
37084
|
+
description: `Select set members by field-value WHERE predicate (repeatable). Same syntax as wh thing query --where; in:[...] accepts at most ${MAX_WHERE_IN_VALUES} values.`
|
|
37085
|
+
}),
|
|
37086
|
+
"source-repo": flag.string({
|
|
37087
|
+
description: "Read selector-backed set members from this source repo (org/repo). The collection is written to the target repo."
|
|
37088
|
+
})
|
|
37089
|
+
};
|
|
37090
|
+
var collectionCreateFlags = {
|
|
37091
|
+
type: flag.string({
|
|
37092
|
+
description: "Collection type: pair, set, or list"
|
|
37093
|
+
}),
|
|
37094
|
+
name: flag.string({
|
|
37095
|
+
description: "Collection local name. Collections are ordinary named things."
|
|
37096
|
+
}),
|
|
37097
|
+
"skip-existing": flag.boolean({
|
|
37098
|
+
description: "No-op if a named collection already exists. Only valid with --name."
|
|
37099
|
+
}),
|
|
37100
|
+
from: flag.string({
|
|
37101
|
+
description: "Initialize from an existing collection wref"
|
|
37102
|
+
}),
|
|
37103
|
+
add: flag.string({
|
|
37104
|
+
multiple: true,
|
|
37105
|
+
description: "With --from, member wrefs to add. May be repeated; comma-separated values are also accepted."
|
|
37106
|
+
}),
|
|
37107
|
+
remove: flag.string({
|
|
37108
|
+
multiple: true,
|
|
37109
|
+
description: "With --from, member wrefs to remove. May be repeated; comma-separated values are also accepted."
|
|
37110
|
+
}),
|
|
37111
|
+
"replace-file": flag.string({
|
|
37112
|
+
description: "With --from, replace membership from a file. Supports newline text, JSON array, JSON object with members, or JSONL."
|
|
37113
|
+
}),
|
|
37114
|
+
"replace-stdin": flag.boolean({
|
|
37115
|
+
description: "With --from, replace membership from stdin. Supports newline text, JSON array, JSON object with members, or JSONL."
|
|
37116
|
+
}),
|
|
37117
|
+
...collectionInputFlags,
|
|
37118
|
+
...collectionQueryFlags,
|
|
37119
|
+
...commonWriteFlags
|
|
37120
|
+
};
|
|
37121
|
+
var collectionMembersFlags = {
|
|
37122
|
+
limit: flag.number({
|
|
37123
|
+
description: "Max members per page (default: 50, max: 500)"
|
|
37124
|
+
}),
|
|
37125
|
+
cursor: flag.string({ description: "Opaque pagination cursor" }),
|
|
37126
|
+
all: flag.boolean({ description: "Fetch all pages" }),
|
|
37127
|
+
version: flag.number({ description: "Specific version number" })
|
|
37128
|
+
};
|
|
37129
|
+
var collectionContainsFlags = {
|
|
37130
|
+
position: flag.number({
|
|
37131
|
+
description: "For list checks, require the member at this zero-based index"
|
|
37132
|
+
}),
|
|
37133
|
+
version: flag.number({
|
|
37134
|
+
description: "Specific collection version number. Member inputs are still pinned before comparison; use pinned @vN members for historical membership checks."
|
|
37135
|
+
}),
|
|
37136
|
+
...collectionInputFlags
|
|
37137
|
+
};
|
|
37138
|
+
var collectionDiffFlags = {
|
|
37139
|
+
mode: flag.string({
|
|
37140
|
+
description: "Diff mode: auto, membership, or ordered"
|
|
37141
|
+
}),
|
|
37142
|
+
"left-version": flag.number({
|
|
37143
|
+
description: "Specific left collection version"
|
|
37144
|
+
}),
|
|
37145
|
+
"right-version": flag.number({
|
|
37146
|
+
description: "Specific right collection version"
|
|
37147
|
+
})
|
|
37148
|
+
};
|
|
37149
|
+
var collectionReviseFlags = {
|
|
37150
|
+
add: flag.string({
|
|
37151
|
+
multiple: true,
|
|
37152
|
+
description: "For set collections, member wrefs to add. May be repeated; comma-separated values are also accepted."
|
|
37153
|
+
}),
|
|
37154
|
+
remove: flag.string({
|
|
37155
|
+
multiple: true,
|
|
37156
|
+
description: "For set collections, member wrefs to remove. May be repeated; comma-separated values are also accepted."
|
|
37157
|
+
}),
|
|
37158
|
+
...collectionInputFlags,
|
|
37159
|
+
...collectionQueryFlags,
|
|
37160
|
+
...commonWriteFlags
|
|
37161
|
+
};
|
|
37162
|
+
var collectionStatsFlags = {
|
|
37163
|
+
version: flag.number({ description: "Specific collection version number" })
|
|
37164
|
+
};
|
|
37165
|
+
function validateCollectionType(value) {
|
|
37166
|
+
if (!value || !COLLECTION_TYPES.includes(value)) {
|
|
37167
|
+
usageError("Usage: wh collection create --type <pair|set|list> --members <wref...>", 'wh collection create --type set --name audited --members Location/a,Location/b -m "audit snapshot"');
|
|
37168
|
+
}
|
|
37169
|
+
return value;
|
|
37170
|
+
}
|
|
37171
|
+
function validateDiffMode(value) {
|
|
37172
|
+
if (value === undefined)
|
|
37173
|
+
return;
|
|
37174
|
+
if (value === "auto" || value === "membership" || value === "ordered") {
|
|
37175
|
+
return value;
|
|
37176
|
+
}
|
|
37177
|
+
usageError("--mode must be one of: auto, membership, ordered", "wh collection diff Set/a Set/b --mode membership");
|
|
37178
|
+
}
|
|
37179
|
+
function collectionQuerySourceFromFlags(flags) {
|
|
37180
|
+
const where = (flags.where ?? []).map(parseWhereFlag);
|
|
37181
|
+
const kind = validateKind(flags.kind);
|
|
37182
|
+
return {
|
|
37183
|
+
...flags.shape ? { shape: flags.shape } : {},
|
|
37184
|
+
...kind ? { kind } : {},
|
|
37185
|
+
...flags.about ? { about: flags.about } : {},
|
|
37186
|
+
...flags.match ? { match: flags.match } : {},
|
|
37187
|
+
...flags.component ? { componentRef: flags.component } : {},
|
|
37188
|
+
...flags["exclude-components"] ? { excludeComponents: flags["exclude-components"] } : {},
|
|
37189
|
+
...where.length > 0 ? { where } : {}
|
|
37190
|
+
};
|
|
37191
|
+
}
|
|
37192
|
+
function parseSourceRepoFlag(value) {
|
|
37193
|
+
if (!value)
|
|
37194
|
+
return;
|
|
37195
|
+
const parsed = splitRepoSlug(value);
|
|
37196
|
+
if (!parsed) {
|
|
37197
|
+
usageError("--source-repo must be an org/repo slug", "wh collection create --type set --name wake-voters --source-repo data/nc-voters --shape Voter --where county=Wake");
|
|
37198
|
+
}
|
|
37199
|
+
return { orgName: parsed.org, repoName: parsed.repo };
|
|
37200
|
+
}
|
|
37201
|
+
function requireQuerySourceForSourceRepo(sourceRepo, querySource, example) {
|
|
37202
|
+
if (!sourceRepo || hasCollectionSelectorAnchor2(querySource))
|
|
37203
|
+
return;
|
|
37204
|
+
usageError("--source-repo requires a selector source", example);
|
|
37205
|
+
}
|
|
37206
|
+
function requireSelectorAnchorForQuerySource(querySource, example) {
|
|
37207
|
+
if (!hasCollectionQuerySource2(querySource) || hasCollectionSelectorAnchor2(querySource)) {
|
|
37208
|
+
return;
|
|
37209
|
+
}
|
|
37210
|
+
usageError("Selector-backed collection sources require shape, about, match, componentRef, or where; kind and exclude-components only narrow an existing selector.", example);
|
|
37211
|
+
}
|
|
37212
|
+
function requireSetForQuerySource(type, source, example) {
|
|
37213
|
+
if (!hasCollectionQuerySource2(source) || type === "set")
|
|
37214
|
+
return;
|
|
37215
|
+
usageError("Selector-backed collection sources are only supported for set collections", example);
|
|
37216
|
+
}
|
|
37217
|
+
function normalizeCreateMembers(type, members) {
|
|
37218
|
+
return type === "set" ? Array.from(new Set(members)) : members;
|
|
37219
|
+
}
|
|
37220
|
+
function hasDeferredMemberSource(flags) {
|
|
37221
|
+
return !!flags.file || !!flags.stdin;
|
|
37222
|
+
}
|
|
37223
|
+
function isMissingCollectionMemberError(error) {
|
|
37224
|
+
const candidate = error;
|
|
37225
|
+
const code = candidate.code ?? candidate.kind;
|
|
37226
|
+
return code === "VALIDATION_ERROR" && /requires (?:at least|exactly) \d+ member/.test(candidate.message ?? "");
|
|
37227
|
+
}
|
|
37228
|
+
function collectionTypeFromWref2(wref) {
|
|
37229
|
+
const local = wref.replace(/^wh:[^/]+\/[^/]+\//, "").replace(/@(?:HEAD|ALL|v\d+)$/, "");
|
|
37230
|
+
const shape = local.split("/")[0]?.toLowerCase();
|
|
37231
|
+
return COLLECTION_TYPES.includes(shape) ? shape : undefined;
|
|
37232
|
+
}
|
|
37233
|
+
function parseCollectionReadRepo(ctx, wrefs) {
|
|
37234
|
+
const allDurable = wrefs.length > 0 && wrefs.every(looksLikeDurableId);
|
|
37235
|
+
return allDurable ? parseOrgRepoOptional(getRepoRef(ctx), ctx.config) : parseOrgRepo(getRepoRef(ctx), ctx.config);
|
|
37236
|
+
}
|
|
37237
|
+
var handleCollectionCreate = async (ctx, { flags, args }) => {
|
|
37238
|
+
if (args.length > 0) {
|
|
37239
|
+
usageError(`Unexpected argument: '${args[0]}'`, "Use --members for explicit collection members: wh collection create --type set --name audited --members Location/a,Location/b");
|
|
37240
|
+
}
|
|
37241
|
+
const { org, repo } = parseOrgRepo(getRepoRef(ctx), ctx.config);
|
|
37242
|
+
const type = validateCollectionType(flags.type);
|
|
37243
|
+
const querySource = collectionQuerySourceFromFlags(flags);
|
|
37244
|
+
const sourceRepo = parseSourceRepoFlag(flags["source-repo"]);
|
|
37245
|
+
const add = parseMemberList(flags.add);
|
|
37246
|
+
const remove = parseMemberList(flags.remove);
|
|
37247
|
+
requireQuerySourceForSourceRepo(sourceRepo, querySource, "wh collection create --type set --name wake-voters --source-repo data/nc-voters --shape Voter --where county=Wake");
|
|
37248
|
+
requireSelectorAnchorForQuerySource(querySource, 'wh collection create --type set --name voters --match "Voter/*" -m "snapshot"');
|
|
37249
|
+
requireSetForQuerySource(type, querySource, 'wh collection create --type set --name voters --match "Voter/*" -m "snapshot"');
|
|
37250
|
+
if (flags.from && hasCollectionQuerySource2(querySource)) {
|
|
37251
|
+
usageError("--from cannot be combined with selector flags", 'wh collection create --type set --name today --from Set/yesterday --add Location/c -m "delta"');
|
|
37252
|
+
}
|
|
37253
|
+
if (flags.from && sourceRepo) {
|
|
37254
|
+
usageError("--from cannot be combined with --source-repo", 'wh collection create --type set --name today --from Set/yesterday --add Location/c -m "delta"');
|
|
37255
|
+
}
|
|
37256
|
+
if (flags.from && (flags.members || flags.file || flags.stdin)) {
|
|
37257
|
+
usageError("--from cannot be combined with --members, --file, or --stdin; use --add/--remove for set deltas or --replace-file/--replace-stdin for full replacement", 'wh collection create --type set --name today --from Set/yesterday --add Location/c -m "delta"');
|
|
37258
|
+
}
|
|
37259
|
+
if ((flags["replace-file"] || flags["replace-stdin"]) && (add.length > 0 || remove.length > 0)) {
|
|
37260
|
+
usageError("--replace-file/--replace-stdin cannot be combined with --add or --remove", 'wh collection create --type set --name today --from Set/yesterday --replace-file members.txt -m "snapshot copy"');
|
|
37261
|
+
}
|
|
37262
|
+
if (!flags.from && (add.length > 0 || remove.length > 0 || flags["replace-file"] || flags["replace-stdin"])) {
|
|
37263
|
+
usageError("--add, --remove, --replace-file, and --replace-stdin require --from", 'wh collection create --type set --name today --from Set/yesterday --add Location/c -m "delta"');
|
|
37264
|
+
}
|
|
37265
|
+
if (!flags.name) {
|
|
37266
|
+
usageError("Collection create requires --name", 'wh collection create --type set --name audited --members Location/a,Location/b -m "audit snapshot"');
|
|
37267
|
+
}
|
|
37268
|
+
if (flags["skip-existing"] && !flags.name) {
|
|
37269
|
+
usageError("--skip-existing requires --name", "wh collection create --type set --name voters --members Voter/a --skip-existing");
|
|
37270
|
+
}
|
|
37271
|
+
const queryBacked = hasCollectionQuerySource2(querySource);
|
|
37272
|
+
const replaceMembers = flags.from && (flags["replace-file"] || flags["replace-stdin"]) ? await readMembersFromSources(ctx, {
|
|
37273
|
+
file: flags["replace-file"],
|
|
37274
|
+
stdin: flags["replace-stdin"],
|
|
37275
|
+
wrefField: flags["wref-field"],
|
|
37276
|
+
label: "replacement members"
|
|
37277
|
+
}) : undefined;
|
|
37278
|
+
const inlineMembers = normalizeCreateMembers(type, parseMemberList(flags.members));
|
|
37279
|
+
if (flags["skip-existing"] && flags.name && !queryBacked && inlineMembers.length === 0 && hasDeferredMemberSource(flags)) {
|
|
37280
|
+
try {
|
|
37281
|
+
const result2 = await ctx.client.collection.create(org, repo, {
|
|
37282
|
+
type,
|
|
37283
|
+
name: flags.name,
|
|
37284
|
+
members: [],
|
|
37285
|
+
skipExisting: true,
|
|
37286
|
+
message: flags.message,
|
|
37287
|
+
committer: flags.committer
|
|
37288
|
+
});
|
|
37289
|
+
writeOutput(ctx, result2, () => renderMutation(ctx, result2));
|
|
37290
|
+
return;
|
|
37291
|
+
} catch (error) {
|
|
37292
|
+
if (!isMissingCollectionMemberError(error)) {
|
|
37293
|
+
throw error;
|
|
37294
|
+
}
|
|
37295
|
+
}
|
|
37296
|
+
}
|
|
37297
|
+
const explicitMembers = await readMembersFromSources(ctx, {
|
|
37298
|
+
members: flags.members,
|
|
37299
|
+
file: flags.from ? undefined : flags.file,
|
|
37300
|
+
stdin: flags.from ? undefined : flags.stdin,
|
|
37301
|
+
wrefField: flags["wref-field"],
|
|
37302
|
+
label: "collection members"
|
|
37303
|
+
});
|
|
37304
|
+
const members = normalizeCreateMembers(type, explicitMembers);
|
|
37305
|
+
if (sourceRepo && members.length > 0) {
|
|
37306
|
+
usageError("--source-repo cannot be combined with explicit members; use canonical wh:org/repo/... member wrefs or omit --source-repo.", "wh collection create --type set --name wake-voters --source-repo data/nc-voters --shape Voter --where county=Wake");
|
|
37307
|
+
}
|
|
37308
|
+
if (!queryBacked && !flags.from) {
|
|
37309
|
+
requireMembers(members, 'wh collection create --type set --name audited --members Location/a,Location/b -m "audit snapshot"');
|
|
37310
|
+
}
|
|
37311
|
+
const result = queryBacked ? sourceRepo ? await ctx.client.collection.create(org, repo, {
|
|
37312
|
+
type,
|
|
37313
|
+
name: flags.name,
|
|
37314
|
+
...flags.from ? { from: flags.from } : {},
|
|
37315
|
+
...add.length > 0 ? { add } : {},
|
|
37316
|
+
...remove.length > 0 ? { remove } : {},
|
|
37317
|
+
...replaceMembers ? { replaceMembers } : {},
|
|
37318
|
+
query: querySource,
|
|
37319
|
+
sourceRepo,
|
|
37320
|
+
skipExisting: flags["skip-existing"],
|
|
37321
|
+
message: flags.message,
|
|
37322
|
+
committer: flags.committer
|
|
37323
|
+
}) : await ctx.client.collection.create(org, repo, {
|
|
37324
|
+
type,
|
|
37325
|
+
name: flags.name,
|
|
37326
|
+
members,
|
|
37327
|
+
...flags.from ? { from: flags.from } : {},
|
|
37328
|
+
...add.length > 0 ? { add } : {},
|
|
37329
|
+
...remove.length > 0 ? { remove } : {},
|
|
37330
|
+
...replaceMembers ? { replaceMembers } : {},
|
|
37331
|
+
query: querySource,
|
|
37332
|
+
skipExisting: flags["skip-existing"],
|
|
37333
|
+
message: flags.message,
|
|
37334
|
+
committer: flags.committer
|
|
37335
|
+
}) : await ctx.client.collection.create(org, repo, {
|
|
37336
|
+
type,
|
|
37337
|
+
name: flags.name,
|
|
37338
|
+
members,
|
|
37339
|
+
...flags.from ? { from: flags.from } : {},
|
|
37340
|
+
...add.length > 0 ? { add } : {},
|
|
37341
|
+
...remove.length > 0 ? { remove } : {},
|
|
37342
|
+
...replaceMembers ? { replaceMembers } : {},
|
|
37343
|
+
skipExisting: flags["skip-existing"],
|
|
37344
|
+
message: flags.message,
|
|
37345
|
+
committer: flags.committer
|
|
37346
|
+
});
|
|
37347
|
+
writeOutput(ctx, result, () => renderMutation(ctx, result));
|
|
37348
|
+
};
|
|
37349
|
+
var handleCollectionMembers = async (ctx, { flags, args }) => {
|
|
37350
|
+
const wref = args[0];
|
|
37351
|
+
if (!wref) {
|
|
37352
|
+
usageError("Usage: wh collection members <wref> [--limit N] [--cursor TOKEN] [--all]", "wh collection members Set/audited --all");
|
|
37353
|
+
}
|
|
37354
|
+
if (flags.cursor && !flags.limit) {
|
|
37355
|
+
usageError("Usage: wh collection members <wref> --limit N --cursor TOKEN", "wh collection members Set/audited --limit 50 --cursor <token>");
|
|
37356
|
+
}
|
|
37357
|
+
const { org, repo } = parseCollectionReadRepo(ctx, [wref]);
|
|
37358
|
+
const boundedLimit = Math.min(flags.limit ?? DEFAULT_PAGE_LIMIT, MAX_PAGE_LIMIT);
|
|
37359
|
+
const pageLimit = flags.all ? Math.min(flags.limit ?? AUTO_PAGE_LIMIT, MAX_PAGE_LIMIT) : boundedLimit;
|
|
37360
|
+
if (flags.all) {
|
|
37361
|
+
const items = [];
|
|
37362
|
+
let cursor = flags.cursor;
|
|
37363
|
+
let snapshotVersion = flags.version;
|
|
37364
|
+
let firstPage;
|
|
37365
|
+
while (true) {
|
|
37366
|
+
const page = await ctx.client.collection.members(org, repo, wref, {
|
|
37367
|
+
version: snapshotVersion,
|
|
37368
|
+
limit: pageLimit,
|
|
37369
|
+
cursor
|
|
37370
|
+
});
|
|
37371
|
+
firstPage ??= {
|
|
37372
|
+
type: page.type,
|
|
37373
|
+
wref: page.wref,
|
|
37374
|
+
version: page.version
|
|
37375
|
+
};
|
|
37376
|
+
items.push(...page.items);
|
|
37377
|
+
snapshotVersion ??= page.version;
|
|
37378
|
+
if (!page.nextCursor)
|
|
37379
|
+
break;
|
|
37380
|
+
cursor = page.nextCursor;
|
|
37381
|
+
}
|
|
37382
|
+
writeCollectionMembersOutput(ctx, {
|
|
37383
|
+
type: firstPage?.type ?? "set",
|
|
37384
|
+
wref: firstPage?.wref ?? wref,
|
|
37385
|
+
version: snapshotVersion ?? firstPage?.version ?? flags.version ?? 1,
|
|
37386
|
+
items,
|
|
37387
|
+
nextCursor: undefined
|
|
37388
|
+
}, { limit: pageLimit, nextCursor: null });
|
|
37389
|
+
return;
|
|
37390
|
+
}
|
|
37391
|
+
const result = await ctx.client.collection.members(org, repo, wref, {
|
|
37392
|
+
version: flags.version,
|
|
37393
|
+
limit: boundedLimit,
|
|
37394
|
+
cursor: flags.cursor
|
|
37395
|
+
});
|
|
37396
|
+
if (result.nextCursor) {
|
|
37397
|
+
emitPartialPageHint(ctx, result.items.length, result.nextCursor, boundedLimit);
|
|
37398
|
+
}
|
|
37399
|
+
writeCollectionMembersOutput(ctx, result, {
|
|
37400
|
+
limit: boundedLimit,
|
|
37401
|
+
nextCursor: result.nextCursor ?? null
|
|
37402
|
+
});
|
|
37403
|
+
};
|
|
37404
|
+
function writeCollectionMembersOutput(ctx, result, page) {
|
|
37405
|
+
if (ctx.format === "json") {
|
|
37406
|
+
const envelope = pageEnvelope(result.items, page);
|
|
37407
|
+
printJson(ctx.out, {
|
|
37408
|
+
type: result.type,
|
|
37409
|
+
wref: result.wref,
|
|
37410
|
+
version: result.version,
|
|
37411
|
+
items: result.items,
|
|
37412
|
+
page: envelope.page
|
|
37413
|
+
});
|
|
37414
|
+
return;
|
|
37415
|
+
}
|
|
37416
|
+
if (ctx.format === "jsonl") {
|
|
37417
|
+
printJsonl(ctx.out, result.items);
|
|
37418
|
+
return;
|
|
37419
|
+
}
|
|
37420
|
+
renderMembers(ctx, result);
|
|
37421
|
+
}
|
|
37422
|
+
var handleCollectionContains = async (ctx, { flags, args }) => {
|
|
37423
|
+
const wref = args[0];
|
|
37424
|
+
if (!wref) {
|
|
37425
|
+
usageError("Usage: wh collection contains <wref> <member...>", "wh collection contains Set/audited Location/a Location/b");
|
|
37426
|
+
}
|
|
37427
|
+
const members = await readMembersFromSources(ctx, {
|
|
37428
|
+
positionals: args.slice(1),
|
|
37429
|
+
members: flags.members,
|
|
37430
|
+
file: flags.file,
|
|
37431
|
+
stdin: flags.stdin,
|
|
37432
|
+
wrefField: flags["wref-field"],
|
|
37433
|
+
label: "collection contains members"
|
|
37434
|
+
});
|
|
37435
|
+
requireMembers(members, "wh collection contains Set/audited Location/a Location/b");
|
|
37436
|
+
const { org, repo } = parseCollectionReadRepo(ctx, [wref]);
|
|
37437
|
+
const result = await ctx.client.collection.contains(org, repo, wref, members, {
|
|
37438
|
+
version: flags.version,
|
|
37439
|
+
position: flags.position
|
|
37440
|
+
});
|
|
37441
|
+
writeOutput(ctx, result, () => renderContains(ctx, result));
|
|
37442
|
+
};
|
|
37443
|
+
var handleCollectionDiff = async (ctx, { flags, args }) => {
|
|
37444
|
+
const [leftWref, rightWref] = args;
|
|
37445
|
+
if (!leftWref || !rightWref) {
|
|
37446
|
+
usageError("Usage: wh collection diff <left-wref> <right-wref> [--mode auto|membership|ordered]", "wh collection diff Set/yesterday Set/today --mode membership");
|
|
37447
|
+
}
|
|
37448
|
+
const { org, repo } = parseCollectionReadRepo(ctx, [leftWref, rightWref]);
|
|
37449
|
+
const result = await ctx.client.collection.diff(org, repo, leftWref, rightWref, {
|
|
37450
|
+
leftVersion: flags["left-version"],
|
|
37451
|
+
rightVersion: flags["right-version"],
|
|
37452
|
+
mode: validateDiffMode(flags.mode)
|
|
37453
|
+
});
|
|
37454
|
+
writeOutput(ctx, result, () => renderDiff(ctx, result));
|
|
37455
|
+
};
|
|
37456
|
+
var handleCollectionRevise = async (ctx, { flags, args }) => {
|
|
37457
|
+
const wref = args[0];
|
|
37458
|
+
if (!wref) {
|
|
37459
|
+
usageError('Usage: wh collection revise <named-wref> --file members.txt -m "message"', 'wh collection revise Set/audited --file members.txt -m "refresh audit set"');
|
|
37460
|
+
}
|
|
37461
|
+
const add = parseMemberList(flags.add);
|
|
37462
|
+
const remove = parseMemberList(flags.remove);
|
|
37463
|
+
if ((add.length > 0 || remove.length > 0) && (flags.members || flags.file || flags.stdin)) {
|
|
37464
|
+
usageError("--add/--remove cannot be combined with replacement members or selector flags", 'wh collection revise Set/audited --add Location/c --remove Location/a -m "delta"');
|
|
37465
|
+
}
|
|
37466
|
+
const members = await readMembersFromSources(ctx, {
|
|
37467
|
+
members: flags.members,
|
|
37468
|
+
file: add.length > 0 || remove.length > 0 ? undefined : flags.file,
|
|
37469
|
+
stdin: add.length > 0 || remove.length > 0 ? undefined : flags.stdin,
|
|
37470
|
+
wrefField: flags["wref-field"],
|
|
37471
|
+
label: "replacement members"
|
|
37472
|
+
});
|
|
37473
|
+
const querySource = collectionQuerySourceFromFlags(flags);
|
|
37474
|
+
const sourceRepo = parseSourceRepoFlag(flags["source-repo"]);
|
|
37475
|
+
requireQuerySourceForSourceRepo(sourceRepo, querySource, 'wh collection revise Set/audited --source-repo data/nc-voters --shape Voter -m "refresh audit set"');
|
|
37476
|
+
requireSelectorAnchorForQuerySource(querySource, 'wh collection revise Set/audited --match "Location/*" -m "refresh audit set"');
|
|
37477
|
+
if (sourceRepo && members.length > 0) {
|
|
37478
|
+
usageError("--source-repo cannot be combined with explicit members; use canonical wh:org/repo/... member wrefs or omit --source-repo.", 'wh collection revise Set/audited --source-repo data/nc-voters --shape Voter -m "refresh audit set"');
|
|
37479
|
+
}
|
|
37480
|
+
if ((add.length > 0 || remove.length > 0) && (members.length > 0 || hasCollectionQuerySource2(querySource))) {
|
|
37481
|
+
usageError("--add/--remove cannot be combined with replacement members or selector flags", 'wh collection revise Set/audited --add Location/c --remove Location/a -m "delta"');
|
|
37482
|
+
}
|
|
37483
|
+
const targetType = collectionTypeFromWref2(wref);
|
|
37484
|
+
if (hasCollectionQuerySource2(querySource) && targetType && targetType !== "set") {
|
|
37485
|
+
usageError("Selector-backed revise requires a Set/<name> target wref", 'wh collection revise Set/audited --match "Location/*" -m "refresh audit set"');
|
|
37486
|
+
}
|
|
37487
|
+
const { org, repo } = parseOrgRepo(getRepoRef(ctx), ctx.config);
|
|
37488
|
+
const queryBacked = hasCollectionQuerySource2(querySource);
|
|
37489
|
+
if (!queryBacked && add.length === 0 && remove.length === 0) {
|
|
37490
|
+
requireMembers(members, 'wh collection revise Set/audited --file members.txt -m "refresh audit set"');
|
|
37491
|
+
}
|
|
37492
|
+
const result = queryBacked ? sourceRepo ? await ctx.client.collection.revise(org, repo, wref, {
|
|
37493
|
+
query: querySource,
|
|
37494
|
+
sourceRepo,
|
|
37495
|
+
message: flags.message,
|
|
37496
|
+
committer: flags.committer
|
|
37497
|
+
}) : await ctx.client.collection.revise(org, repo, wref, {
|
|
37498
|
+
members,
|
|
37499
|
+
query: querySource,
|
|
37500
|
+
message: flags.message,
|
|
37501
|
+
committer: flags.committer
|
|
37502
|
+
}) : await ctx.client.collection.revise(org, repo, wref, {
|
|
37503
|
+
members,
|
|
37504
|
+
...add.length > 0 ? { add } : {},
|
|
37505
|
+
...remove.length > 0 ? { remove } : {},
|
|
37506
|
+
message: flags.message,
|
|
37507
|
+
committer: flags.committer
|
|
37508
|
+
});
|
|
37509
|
+
writeOutput(ctx, result, () => renderMutation(ctx, result));
|
|
37510
|
+
};
|
|
37511
|
+
var handleCollectionStats = async (ctx, { flags, args }) => {
|
|
37512
|
+
const wref = args[0];
|
|
37513
|
+
if (!wref) {
|
|
37514
|
+
usageError("Usage: wh collection stats <wref>", "wh collection stats Set/audited");
|
|
37515
|
+
}
|
|
37516
|
+
const { org, repo } = parseCollectionReadRepo(ctx, [wref]);
|
|
37517
|
+
const result = await ctx.client.collection.stats(org, repo, wref, {
|
|
37518
|
+
version: flags.version
|
|
37519
|
+
});
|
|
37520
|
+
writeOutput(ctx, result, () => renderStats(ctx, result));
|
|
37521
|
+
};
|
|
37522
|
+
var COLLECTION_DOMAIN = defineDomain({
|
|
37523
|
+
name: "collection",
|
|
37524
|
+
summary: "Create, inspect, compare, and revise WarmHub collections (Pair, Set, List).",
|
|
37525
|
+
group: "resource",
|
|
37526
|
+
verbs: {
|
|
37527
|
+
create: {
|
|
37528
|
+
summary: "Create a collection thing from explicit members or a set selector",
|
|
37529
|
+
args: "",
|
|
37530
|
+
flags: collectionCreateFlags,
|
|
37531
|
+
examples: [
|
|
37532
|
+
'wh collection create --type set --name audited --members Location/a,Location/b -m "audit snapshot"',
|
|
37533
|
+
'wh collection create --type set --name voters --match "Voter/*" -m "voter snapshot"',
|
|
37534
|
+
'wh collection create --type set --name wake-voters --shape Voter --where state=NC --where county=Wake -m "snapshot Wake County voters"',
|
|
37535
|
+
'wh collection create --type set --name today --from Set/yesterday --add Location/c --remove Location/a -m "delta"'
|
|
37536
|
+
],
|
|
37537
|
+
handler: handleCollectionCreate
|
|
37538
|
+
},
|
|
37539
|
+
revise: {
|
|
37540
|
+
summary: "Revise a named collection by replacement, selector, or set delta",
|
|
37541
|
+
args: "<named-wref>",
|
|
37542
|
+
flags: collectionReviseFlags,
|
|
37543
|
+
examples: [
|
|
37544
|
+
'wh collection revise Set/audited --file members.txt -m "refresh audit set"',
|
|
37545
|
+
'wh collection revise Set/audited --match "Location/*" -m "refresh audit set"',
|
|
37546
|
+
'wh collection revise Set/audited --add Location/c --remove Location/a -m "delta"'
|
|
37547
|
+
],
|
|
37548
|
+
handler: handleCollectionRevise
|
|
37549
|
+
},
|
|
37550
|
+
members: {
|
|
37551
|
+
summary: "List collection members with pagination",
|
|
37552
|
+
args: "<wref>",
|
|
37553
|
+
flags: collectionMembersFlags,
|
|
37554
|
+
examples: ["wh collection members Set/audited --all"],
|
|
37555
|
+
handler: handleCollectionMembers
|
|
37556
|
+
},
|
|
37557
|
+
contains: {
|
|
37558
|
+
summary: "Check collection membership for one or more wrefs",
|
|
37559
|
+
args: "<wref> <member...>",
|
|
37560
|
+
flags: collectionContainsFlags,
|
|
37561
|
+
examples: ["wh collection contains Set/audited Location/a Location/b"],
|
|
37562
|
+
handler: handleCollectionContains
|
|
37563
|
+
},
|
|
37564
|
+
diff: {
|
|
37565
|
+
summary: "Compare two collections by membership or order",
|
|
37566
|
+
args: "<left-wref> <right-wref>",
|
|
37567
|
+
flags: collectionDiffFlags,
|
|
37568
|
+
examples: [
|
|
37569
|
+
"wh collection diff Set/yesterday Set/today --mode membership"
|
|
37570
|
+
],
|
|
37571
|
+
handler: handleCollectionDiff
|
|
37572
|
+
},
|
|
37573
|
+
stats: {
|
|
37574
|
+
summary: "Summarize collection size and identity",
|
|
37575
|
+
args: "<wref>",
|
|
37576
|
+
flags: collectionStatsFlags,
|
|
37577
|
+
examples: ["wh collection stats Set/audited"],
|
|
37578
|
+
handler: handleCollectionStats
|
|
37579
|
+
}
|
|
37580
|
+
}
|
|
37581
|
+
});
|
|
37582
|
+
|
|
36583
37583
|
// ../../packages/warmhub-cli/src/domains/commit-submit-flags.ts
|
|
36584
37584
|
var createFlags3 = {
|
|
36585
37585
|
ops: flag.string({
|
|
@@ -36612,7 +37612,7 @@ var createFlags3 = {
|
|
|
36612
37612
|
}),
|
|
36613
37613
|
message: flag.string({ short: "m", description: "Commit message" }),
|
|
36614
37614
|
committer: flag.string({
|
|
36615
|
-
description: "Committer
|
|
37615
|
+
description: "Committer wref (shape or shaped thing; e.g. Agent/bot-1)"
|
|
36616
37616
|
}),
|
|
36617
37617
|
add: flag.string({
|
|
36618
37618
|
description: "Add a new thing (bare name — use --shape to set the shape). Repeatable; pair each --add with its own --data. For >20 ops, use --file <path>.",
|
|
@@ -36636,7 +37636,7 @@ var createFlags3 = {
|
|
|
36636
37636
|
multiple: true
|
|
36637
37637
|
}),
|
|
36638
37638
|
about: flag.string({
|
|
36639
|
-
description: "Target thing for assertions. Repeatable; one per --add, or a single value broadcast to all.",
|
|
37639
|
+
description: "Target shape or shaped thing for assertions. Repeatable; one per --add, or a single value broadcast to all.",
|
|
36640
37640
|
multiple: true
|
|
36641
37641
|
}),
|
|
36642
37642
|
reason: flag.string({
|
|
@@ -36644,7 +37644,10 @@ var createFlags3 = {
|
|
|
36644
37644
|
multiple: true
|
|
36645
37645
|
}),
|
|
36646
37646
|
type: flag.string({
|
|
36647
|
-
description: "Collection type: pair,
|
|
37647
|
+
description: "Collection type: pair, set, list"
|
|
37648
|
+
}),
|
|
37649
|
+
name: flag.string({
|
|
37650
|
+
description: "Collection name for --type shorthand"
|
|
36648
37651
|
}),
|
|
36649
37652
|
members: flag.string({
|
|
36650
37653
|
description: "Collection members (comma-separated wrefs)"
|
|
@@ -36789,32 +37792,12 @@ function emitTemplateHint(ctx, operationType) {
|
|
|
36789
37792
|
const assertionArgs = operationType === "add" ? "--kind assertion --about <Target/FILL_IN>" : "--kind assertion";
|
|
36790
37793
|
ctx.err(`Template note: shapes define payload fields. To scaffold an assertion, rerun with ${assertionArgs}.`);
|
|
36791
37794
|
}
|
|
36792
|
-
var COLLECTION_ABOUT_PREFIX_RE = /^(pair|
|
|
37795
|
+
var COLLECTION_ABOUT_PREFIX_RE = /^(pair|set|list):(.*)$/;
|
|
36793
37796
|
function parseCollectionAboutFlag(raw) {
|
|
36794
37797
|
const match = COLLECTION_ABOUT_PREFIX_RE.exec(raw);
|
|
36795
37798
|
if (!match)
|
|
36796
37799
|
return raw;
|
|
36797
|
-
|
|
36798
|
-
const members = match[2].split(",").map((m) => m.trim()).filter(Boolean);
|
|
36799
|
-
switch (tag) {
|
|
36800
|
-
case "pair":
|
|
36801
|
-
if (members.length !== 2) {
|
|
36802
|
-
throw new CliError(2 /* UserInput */, "USER_INPUT", `pair requires exactly 2 members, got ${members.length}`, undefined, "Example: --about pair:Location/a,Location/b");
|
|
36803
|
-
}
|
|
36804
|
-
break;
|
|
36805
|
-
case "triple":
|
|
36806
|
-
if (members.length !== 3) {
|
|
36807
|
-
throw new CliError(2 /* UserInput */, "USER_INPUT", `triple requires exactly 3 members, got ${members.length}`, undefined, "Example: --about triple:Location/a,Location/b,Location/c");
|
|
36808
|
-
}
|
|
36809
|
-
break;
|
|
36810
|
-
case "set":
|
|
36811
|
-
case "list":
|
|
36812
|
-
if (members.length === 0) {
|
|
36813
|
-
throw new CliError(2 /* UserInput */, "USER_INPUT", `${tag} requires at least 1 member`, undefined, `Example: --about ${tag}:Location/a,Location/b`);
|
|
36814
|
-
}
|
|
36815
|
-
break;
|
|
36816
|
-
}
|
|
36817
|
-
return { [tag]: members };
|
|
37800
|
+
throw new CliError(2 /* UserInput */, "USER_INPUT", COLLECTION_ABOUT_REMOVED_MESSAGE, undefined, "Use wh commit submit --file with a named collection add followed by an assertion add.");
|
|
36818
37801
|
}
|
|
36819
37802
|
var handleTemplate = async (ctx, { flags, args }) => {
|
|
36820
37803
|
const shapeNames = args;
|
|
@@ -37618,7 +38601,7 @@ var handleSubmit = async (ctx, { flags, args }) => {
|
|
|
37618
38601
|
throw new CliError(2 /* UserInput */, "USER_INPUT", `Invalid --kind "${k}". Must be one of: ${validKinds.join(", ")}`);
|
|
37619
38602
|
}
|
|
37620
38603
|
}
|
|
37621
|
-
const validCollectionTypes = ["pair", "
|
|
38604
|
+
const validCollectionTypes = ["pair", "set", "list"];
|
|
37622
38605
|
if (flags.type && !validCollectionTypes.includes(flags.type)) {
|
|
37623
38606
|
throw new CliError(2 /* UserInput */, "USER_INPUT", `Invalid --type "${flags.type}". Must be one of: ${validCollectionTypes.join(", ")}`);
|
|
37624
38607
|
}
|
|
@@ -37650,11 +38633,14 @@ var handleSubmit = async (ctx, { flags, args }) => {
|
|
|
37650
38633
|
if (streamInput) {
|
|
37651
38634
|
operations = [];
|
|
37652
38635
|
} else if (collectionType) {
|
|
38636
|
+
if (!flags.name) {
|
|
38637
|
+
usageError("Usage: wh commit submit --type <pair|set|list> --name <collection-name> --members <wref1,wref2,...>", "wh commit submit --type pair --name location-distance --members Location/a,Location/b");
|
|
38638
|
+
}
|
|
37653
38639
|
if (!flags.members) {
|
|
37654
|
-
usageError("Usage: wh commit submit --type <pair|
|
|
38640
|
+
usageError("Usage: wh commit submit --type <pair|set|list> --name <collection-name> --members <wref1,wref2,...>", "wh commit submit --type pair --name location-distance --members Location/a,Location/b");
|
|
37655
38641
|
}
|
|
37656
38642
|
const members = flags.members.split(",").map((m) => m.trim()).filter(Boolean);
|
|
37657
|
-
const arityMap = { pair: 2
|
|
38643
|
+
const arityMap = { pair: 2 };
|
|
37658
38644
|
const expected = arityMap[collectionType];
|
|
37659
38645
|
if (expected && members.length !== expected) {
|
|
37660
38646
|
throw new CliError(2 /* UserInput */, "USER_INPUT", `${collectionType} requires exactly ${expected} members, got ${members.length}`);
|
|
@@ -37667,6 +38653,7 @@ var handleSubmit = async (ctx, { flags, args }) => {
|
|
|
37667
38653
|
operation: "add",
|
|
37668
38654
|
kind: "collection",
|
|
37669
38655
|
type: collectionType,
|
|
38656
|
+
name: flags.name,
|
|
37670
38657
|
members
|
|
37671
38658
|
}
|
|
37672
38659
|
];
|
|
@@ -37817,8 +38804,8 @@ var COMMIT_DOMAIN = defineDomain({
|
|
|
37817
38804
|
`printf '%s\\n' '{"operation":"add","kind":"thing","name":"Player/alice","data":{"score":1}}' | wh commit submit --stream --stream-id bulk-2026-06-04 --skip-existing --repo acme/world -m "stdin stream"`,
|
|
37818
38805
|
'wh commit submit --file dataset.jsonl --stream-id bulk-2026-06-04 --skip-existing --progress -m "bulk stream"',
|
|
37819
38806
|
"wh shape template Session HypothesisCandidate -o ops.json",
|
|
37820
|
-
"wh commit submit --type pair --members Location/a,Location/b",
|
|
37821
|
-
'wh commit submit --type set --members Location/a,Location/b,Location/c -m "Create location set"'
|
|
38807
|
+
"wh commit submit --type pair --name location-distance --members Location/a,Location/b",
|
|
38808
|
+
'wh commit submit --type set --name active-locations --members Location/a,Location/b,Location/c -m "Create location set"'
|
|
37822
38809
|
],
|
|
37823
38810
|
notes: [
|
|
37824
38811
|
"Need to build an ops file? Run `wh shape template <Shape>` to scaffold the JSON from a shape definition, edit the FILL_IN placeholders, then pass it to `--file`.",
|
|
@@ -37832,7 +38819,7 @@ var COMMIT_DOMAIN = defineDomain({
|
|
|
37832
38819
|
import {
|
|
37833
38820
|
existsSync as existsSync7,
|
|
37834
38821
|
mkdirSync as mkdirSync6,
|
|
37835
|
-
readFileSync as
|
|
38822
|
+
readFileSync as readFileSync7,
|
|
37836
38823
|
renameSync as renameSync3,
|
|
37837
38824
|
rmSync as rmSync4,
|
|
37838
38825
|
writeFileSync as writeFileSync6
|
|
@@ -37868,7 +38855,7 @@ function loadInstallSnapshotCacheRaw(repoSlug) {
|
|
|
37868
38855
|
if (!path2 || !existsSync7(path2))
|
|
37869
38856
|
return null;
|
|
37870
38857
|
try {
|
|
37871
|
-
const raw =
|
|
38858
|
+
const raw = readFileSync7(path2, "utf-8");
|
|
37872
38859
|
return JSON.parse(raw);
|
|
37873
38860
|
} catch {
|
|
37874
38861
|
return null;
|
|
@@ -38638,7 +39625,7 @@ function formatReservedNameWarning(name) {
|
|
|
38638
39625
|
}
|
|
38639
39626
|
|
|
38640
39627
|
// ../../packages/warmhub-cli/src/manifest/parser.ts
|
|
38641
|
-
import { existsSync as existsSync8, readFileSync as
|
|
39628
|
+
import { existsSync as existsSync8, readFileSync as readFileSync8 } from "node:fs";
|
|
38642
39629
|
import { resolve } from "node:path";
|
|
38643
39630
|
function parseComponentPackage(dirPath) {
|
|
38644
39631
|
const rootDir = resolve(dirPath);
|
|
@@ -38651,7 +39638,7 @@ function parseComponentPackage(dirPath) {
|
|
|
38651
39638
|
}
|
|
38652
39639
|
let componentRaw;
|
|
38653
39640
|
try {
|
|
38654
|
-
componentRaw = JSON.parse(
|
|
39641
|
+
componentRaw = JSON.parse(readFileSync8(componentJsonPath, "utf-8"));
|
|
38655
39642
|
} catch (err) {
|
|
38656
39643
|
errors.push(`Failed to parse warmhub/component.json: ${err instanceof Error ? err.message : String(err)}`);
|
|
38657
39644
|
return { ok: false, errors, warnings };
|
|
@@ -38666,7 +39653,7 @@ function parseComponentPackage(dirPath) {
|
|
|
38666
39653
|
}
|
|
38667
39654
|
let manifestRaw;
|
|
38668
39655
|
try {
|
|
38669
|
-
manifestRaw = JSON.parse(
|
|
39656
|
+
manifestRaw = JSON.parse(readFileSync8(manifestJsonPath, "utf-8"));
|
|
38670
39657
|
} catch (err) {
|
|
38671
39658
|
errors.push(`Failed to parse warmhub/manifest.json: ${err instanceof Error ? err.message : String(err)}`);
|
|
38672
39659
|
return { ok: false, errors, warnings };
|
|
@@ -38867,7 +39854,7 @@ function formatLifecycleUrl(url, colors) {
|
|
|
38867
39854
|
}
|
|
38868
39855
|
|
|
38869
39856
|
// ../../packages/warmhub-cli/src/domains/component-utils.ts
|
|
38870
|
-
import { readFileSync as
|
|
39857
|
+
import { readFileSync as readFileSync9 } from "node:fs";
|
|
38871
39858
|
function isRegisteredComponentSource(source) {
|
|
38872
39859
|
return /^[a-z0-9-]+\/[a-z0-9-]+$/.test(source);
|
|
38873
39860
|
}
|
|
@@ -38907,7 +39894,7 @@ function resolveMintedTokensFlag(args) {
|
|
|
38907
39894
|
function readManifestArg(path2) {
|
|
38908
39895
|
let raw;
|
|
38909
39896
|
try {
|
|
38910
|
-
raw =
|
|
39897
|
+
raw = readFileSync9(path2, "utf8");
|
|
38911
39898
|
} catch {
|
|
38912
39899
|
throw new CliError(2 /* UserInput */, "USER_INPUT", `Cannot read manifest file: ${path2}`, undefined, "Pass --manifest <path to warmhub/manifest.json>");
|
|
38913
39900
|
}
|
|
@@ -41492,245 +42479,7 @@ var ORG_DOMAIN = defineDomain({
|
|
|
41492
42479
|
});
|
|
41493
42480
|
|
|
41494
42481
|
// ../../packages/warmhub-cli/src/domains/prime-content.md
|
|
41495
|
-
var prime_content_default = `# WarmHub CLI Context
|
|
41496
|
-
> **Context Recovery**: Run \`wh prime\` after compaction or new session
|
|
41497
|
-
|
|
41498
|
-
## Environment
|
|
41499
|
-
{{REPO_LINE}}
|
|
41500
|
-
|
|
41501
|
-
## Core Concepts
|
|
41502
|
-
- **Thing**: A named entity versioned by write operations. **Assertion**: A claim about a thing with shape-validated data.
|
|
41503
|
-
- **Shape**: Schema defining data structure. **Write**: One or more add/revise/retract operations with per-operation results.
|
|
41504
|
-
- **wref**: Reference as \`Shape/name\` (e.g., \`Player/alice\`). Cross-repo: \`wh:org/repo/Shape/name\`.
|
|
41505
|
-
|
|
41506
|
-
## Versioned Things
|
|
41507
|
-
- \`Shape/name\` identifies the logical thing. \`Shape/name@vN\` pins an exact version.
|
|
41508
|
-
- Read surfaces may show pinned wrefs (\`@vN\`) in data. Treat them as version metadata, not a different thing.
|
|
41509
|
-
|
|
41510
|
-
## Key Workflows
|
|
41511
|
-
|
|
41512
|
-
**Write data** (discover shapes → scaffold ops → submit):
|
|
41513
|
-
\`\`\`bash
|
|
41514
|
-
wh shape list --repo org/repo # list available shapes
|
|
41515
|
-
wh shape view ShapeName --repo org/repo # inspect fields
|
|
41516
|
-
wh shape template ShapeName -o ops.json --repo org/repo # scaffold write ops (supports --kind assertion)
|
|
41517
|
-
# edit ops.json — fill FILL_IN placeholders — then:
|
|
41518
|
-
wh commit submit --file ops.json -m "msg" --repo org/repo # submit operations (bare \`wh commit\` also works)
|
|
41519
|
-
# or single assertion (no file needed):
|
|
41520
|
-
wh assertion create --shape ShapeName --about Target/name --name my-assertion --data '{"field":1}' --repo org/repo
|
|
41521
|
-
# Relay failed operation details when present. Never hand-guess ops JSON — use \`wh shape template <Shape>\`.
|
|
41522
|
-
\`\`\`
|
|
41523
|
-
|
|
41524
|
-
**Read data:**
|
|
41525
|
-
\`\`\`bash
|
|
41526
|
-
wh thing list --repo org/repo # all things at HEAD
|
|
41527
|
-
wh thing view Shape/name --repo org/repo # inspect a thing
|
|
41528
|
-
wh thing query --shape MyShape --repo org/repo # find things by shape
|
|
41529
|
-
wh thing about Shape/name --repo org/repo # assertions about a thing
|
|
41530
|
-
wh assertion list --repo org/repo # all assertions at HEAD
|
|
41531
|
-
wh thing history Shape/name --repo org/repo # version history
|
|
41532
|
-
|
|
41533
|
-
# Batch read — wh thing view is variadic (max 500 wrefs/call):
|
|
41534
|
-
wh thing view Player/alice Player/bob # variadic positionals
|
|
41535
|
-
wh thing view --file wrefs.txt --json # one wref per line
|
|
41536
|
-
cat wrefs.txt | wh thing view --format jsonl # one JSON line per *deduped* requested wref
|
|
41537
|
-
\`\`\`
|
|
41538
|
-
|
|
41539
|
-
## Wref Quick Reference
|
|
41540
|
-
|
|
41541
|
-
**Batch tokens** (in write operations):
|
|
41542
|
-
- \`$N\` in last segment of ADD name — generates an opaque stream-scoped identifier
|
|
41543
|
-
- \`#N\` anywhere — references value allocated by \`$N\`
|
|
41544
|
-
- Example: \`Player/player-$1\` + about \`Player/player-#1\` → \`Player/player-a1b2c3d4e5f6a7b8\`
|
|
41545
|
-
|
|
41546
|
-
## Command Reference
|
|
41547
|
-
|
|
41548
|
-
**Global flags**: \`--repo\`, \`--format\`, \`--json\`, \`--live\`
|
|
41549
|
-
### thing — Thing operations
|
|
41550
|
-
- \`wh thing list [--shape] [--kind] [--match] [--include-retracted]\` — Current HEAD state
|
|
41551
|
-
- \`wh thing view [<wref>...] [--file <path>] [--version] [--depth] [--include-retracted]\` — Thing details. Variadic: singleton routes to \`thing.get\`; multiple wrefs or \`--file\` routes to batch fetch (max 500). Wrefs from positionals, \`--file <path>\` (use \`--file=-\` for stdin), bare \`-\` positional (stdin), or piped stdin when no other source given. Explicit positionals never implicitly consume stdin. \`--version\` implies \`--include-retracted\`. Batch returns \`{ requested, items, missing }\` in \`--json\`; \`--format jsonl\` emits one record per deduped requested wref.
|
|
41552
|
-
- \`wh thing history [wref] [--shape] [--about] [--include-retracted]\` — Version history
|
|
41553
|
-
- \`wh thing resolve <wref>\` — Resolve wref
|
|
41554
|
-
- \`wh thing create <name|Shape/name> --data <json-object> [--shape] [--message] [--committer]\` — Create
|
|
41555
|
-
- \`wh thing revise <name> [--data] [--message] [--committer] [--expected-version]\` — Revise (CONFLICT if HEAD≠n)
|
|
41556
|
-
- \`wh thing retract <wref> -m <message> [--reason] [--kind]\` — Retract
|
|
41557
|
-
- \`wh thing query [--shape] [--kind] [--about] [--match]\` — Query by filters
|
|
41558
|
-
- \`wh thing search <query> [--shape] [--kind] [--about] [--mode]\` — Search text
|
|
41559
|
-
- \`wh thing rename <Shape/oldName> <newName>\` — Rename
|
|
41560
|
-
- \`wh thing refs <wref> [--inbound] [--outbound] [--field]\` — Show field references; use \`wh thing about\` for assertions about a thing
|
|
41561
|
-
- \`wh thing about <wref> [--shape] [--match] [--depth] [--resolve-collections] [--limit] [--include-retracted]\` — Show assertions about the target identity; \`--resolve-collections\` expands collection members for bare/@HEAD/@ALL inputs, not pinned @vN
|
|
41562
|
-
|
|
41563
|
-
### commit — Write operations
|
|
41564
|
-
- \`wh commit submit [--ops|--file|--add|--revise|--retract] [--kind] [--data] [--reason] [--expected-version] [--chunk-size] [--skip-existing] [--progress] [--stream-id]\` — Submit operations (bare \`wh commit\` is equivalent). Use \`--file ops.jsonl --stream-id <id> --chunk-size 5000 --skip-existing\` for bulk ingest.
|
|
41565
|
-
- \`wh shape template <shape> [shape2 ...] [--kind] [--operation add|revise|retract] [-o file]\` — Generate sample ops
|
|
41566
|
-
|
|
41567
|
-
### assertion — Assertion operations
|
|
41568
|
-
- \`wh assertion list [--about wref] [--shape] [--match] [--include-retracted]\` — Browse assertions
|
|
41569
|
-
- \`wh assertion view <wref> [--version] [--include-retracted]\` — Assertion details
|
|
41570
|
-
- \`wh assertion create [--name] [--shape] [--data] [--about] [--message] [--committer]\` — Create assertion
|
|
41571
|
-
- \`wh assertion revise <wref> --data <json> [--message] [--committer]\` — Revise assertion
|
|
41572
|
-
- \`wh assertion retract <wref> -m <message> [--reason] [--committer]\` — Retract assertion
|
|
41573
|
-
- \`wh assertion history <wref> [--include-retracted]\` — Assertion history
|
|
41574
|
-
|
|
41575
|
-
### shape — Shape management
|
|
41576
|
-
- \`wh shape list [--match] [--include-retracted]\` — List all shapes
|
|
41577
|
-
- \`wh shape view <name> [--include-retracted]\` — Shape details
|
|
41578
|
-
- \`wh shape revise <name> [--fields]\` — Revise shape
|
|
41579
|
-
- \`wh shape create <name> [--fields]\` — Create shape
|
|
41580
|
-
- \`wh shape retract <name> -m <message> [--reason]\` — Retract shape
|
|
41581
|
-
- \`wh shape history <name> [--include-retracted]\` — Shape history
|
|
41582
|
-
- \`wh shape rename <oldName> <newName>\` — Rename shape
|
|
41583
|
-
|
|
41584
|
-
### repo — Repository management
|
|
41585
|
-
- \`wh repo create <org/name> [--display-name] [--description] [--visibility]\` — Create repo
|
|
41586
|
-
- \`wh repo list [org]\` — List repos
|
|
41587
|
-
- \`wh repo view [org/repo]\` — Repo details
|
|
41588
|
-
|
|
41589
|
-
### org — Organization management
|
|
41590
|
-
- \`wh org create <name> [--display-name]\` — Create a new organization
|
|
41591
|
-
- \`wh org view <name>\` — View organization details (alias: info)
|
|
41592
|
-
- \`wh org list\` — List all organizations
|
|
41593
|
-
|
|
41594
|
-
### sub — Subscription management
|
|
41595
|
-
- \`wh sub create <name> [flags]\` — Create a subscription
|
|
41596
|
-
- \`wh sub view <name>\` — View subscription details
|
|
41597
|
-
- \`wh sub list\` — List all subscriptions
|
|
41598
|
-
- \`wh sub log <name>\` — Tail subscription delivery feed
|
|
41599
|
-
- \`wh sub attempts <runId>\` — Show attempt history for a run
|
|
41600
|
-
- \`wh sub pause <name>\` — Pause a subscription
|
|
41601
|
-
- \`wh sub resume <name>\` — Resume a paused subscription
|
|
41602
|
-
- \`wh sub bind <name> [--credentials]\` — Bind a credential set to a subscription for webhook auth
|
|
41603
|
-
- \`wh sub unbind <name>\` — Remove credential binding from a subscription
|
|
41604
|
-
- \`wh sub delete <name>\` — Delete a subscription
|
|
41605
|
-
|
|
41606
|
-
### notifications — Action notification listing
|
|
41607
|
-
- \`wh notifications [--limit] [--since]\` — List repo-scoped action notifications
|
|
41608
|
-
|
|
41609
|
-
### credential — Credential set management
|
|
41610
|
-
- \`wh credential create <name> [--repo org/repo | --org org] [--scope] [--description]\` — Create an empty credential set
|
|
41611
|
-
- \`wh credential list [--repo org/repo | --org org]\` — List credential sets accessible from a repo or org
|
|
41612
|
-
- \`wh credential view <name> [--repo org/repo | --org org]\` — View a credential set (key names only, no values)
|
|
41613
|
-
- \`wh credential delete <name> [--repo org/repo | --org org]\` — Delete a credential set and its Vault object
|
|
41614
|
-
- \`wh credential set <setName> [<keyName>] [--repo org/repo | --org org] [--value]\` — Set credential key(s). With \`<keyName>\`: single-key form (reads value from \`--value\` or stdin). Without \`<keyName>\`: batch form (reads JSON object from stdin, e.g. \`{"KEY":"val"}\`)
|
|
41615
|
-
- \`wh credential unset <setName> <keyName> [--repo org/repo | --org org]\` — Remove a key from a credential set
|
|
41616
|
-
- \`wh credential audit <setName> [--repo org/repo | --org org]\` — View audit log for a credential set
|
|
41617
|
-
- \`wh credential revoke <setName> [--repo org/repo | --org org] [--reason]\` — Revoke a credential set (blocks new binds and strips auth from existing webhook deliveries)
|
|
41618
|
-
|
|
41619
|
-
### component — Component management
|
|
41620
|
-
- \`wh component validate <path>\` — Validate package
|
|
41621
|
-
- \`wh component install <org/name>\` — Install a registered component
|
|
41622
|
-
- \`wh component register <name> --org <org> --manifest <path> [flags]\` — Register component identity
|
|
41623
|
-
- \`wh component unregister <org/name>\` — Remove a registered component identity
|
|
41624
|
-
- \`wh component registry list --org <org>\` — List registered components
|
|
41625
|
-
- \`wh component registry view <org/name>\` — View a registered component
|
|
41626
|
-
- \`wh component registry update <org/name> [flags]\` — Update a registered component
|
|
41627
|
-
- \`wh component list\` — List installed components
|
|
41628
|
-
- \`wh component update <org/name>\` — Update installed component
|
|
41629
|
-
- \`wh component view <org/name>\` — Show component details (alias: show)
|
|
41630
|
-
- \`wh component doctor <org/name>\` — Run component health checks
|
|
41631
|
-
- \`wh component teardown <org/name>\` — Pause component subscriptions
|
|
41632
|
-
|
|
41633
|
-
### Getting More Info
|
|
41634
|
-
- \`wh help\` — full help overview
|
|
41635
|
-
- \`wh <domain>\` — list verbs for a domain
|
|
41636
|
-
- \`wh <domain> <verb> --help\` — verb details with flags and examples
|
|
41637
|
-
- \`wh help --format json\` — full CLI spec as JSON (best for agents)
|
|
41638
|
-
|
|
41639
|
-
## Common Workflows
|
|
41640
|
-
|
|
41641
|
-
**Explore a repo:**
|
|
41642
|
-
\`\`\`bash
|
|
41643
|
-
wh thing list --repo org/repo # see all things in HEAD
|
|
41644
|
-
wh thing view Shape/name --repo org/repo # inspect a specific thing
|
|
41645
|
-
wh thing history Shape/name --repo org/repo # inspect version history
|
|
41646
|
-
wh thing about Shape/name # assertions about a thing
|
|
41647
|
-
\`\`\`
|
|
41648
|
-
|
|
41649
|
-
**Create an assertion** (most common write):
|
|
41650
|
-
\`\`\`bash
|
|
41651
|
-
# --about takes a wref (Shape/name). Use \`wh thing list\` to find valid wrefs.
|
|
41652
|
-
wh assertion create --shape MyShape --about TargetShape/target-name \\
|
|
41653
|
-
--name my-assertion --data '{"field_a":1,"field_b":"value"}' --repo org/repo
|
|
41654
|
-
# Output includes per-operation status; relay failures when present.
|
|
41655
|
-
\`\`\`
|
|
41656
|
-
|
|
41657
|
-
**Create via write entrypoint** (alternative, supports batches and streams):
|
|
41658
|
-
\`\`\`bash
|
|
41659
|
-
wh commit submit --add my-item --shape MyShape --kind assertion \\
|
|
41660
|
-
--about TargetShape/target-name --data '{"field_a":1}' --repo org/repo
|
|
41661
|
-
\`\`\`
|
|
41662
|
-
|
|
41663
|
-
**Batch write via file** (generate template → edit → submit):
|
|
41664
|
-
\`\`\`bash
|
|
41665
|
-
wh shape template Hypothesis Evidence -o ops.json # add --kind assertion --about TargetShape/name for assertions
|
|
41666
|
-
# edit ops.json — fill FILL_IN placeholders
|
|
41667
|
-
wh commit submit --file ops.json -m "batch update" # submit all operations (bare \`wh commit\` is equivalent)
|
|
41668
|
-
# --file format: docs.warmhub.ai/cli-reference/commit-operations
|
|
41669
|
-
\`\`\`
|
|
41670
|
-
|
|
41671
|
-
**Bulk write (JSONL stream, >1k ops)** — one chunked stream beats per-record commits (~60× faster):
|
|
41672
|
-
\`\`\`bash
|
|
41673
|
-
wh shape template MyShape -o ops.jsonl # one op per line (.jsonl)
|
|
41674
|
-
ID="bulk-$(date +%s)" # choose your own; set it up front so reruns are safe
|
|
41675
|
-
wh commit submit --file ops.jsonl --stream-id "$ID" --chunk-size 5000 \\
|
|
41676
|
-
--skip-existing --progress -m "bulk ingest" --repo org/repo
|
|
41677
|
-
# --chunk-size: ops per append chunk (default 1000, max 10000); chunk≈1 is ~60× slower
|
|
41678
|
-
# --skip-existing: skips already-written add ops (drops per-row read-before-write)
|
|
41679
|
-
# Add-stream restart: rerun the WHOLE file with the SAME --stream-id.
|
|
41680
|
-
# Fixed-name adds are idempotent via --skip-existing; tokenized ($N/#N) names
|
|
41681
|
-
# derive from streamId, so rerun rebuilds token state. Omitting --stream-id is
|
|
41682
|
-
# rejected because reruns must reuse the same token namespace. Mid-stream resume
|
|
41683
|
-
# is not a CLI mode. Mixed revise/retract JSONL streams are not full-rerun safe
|
|
41684
|
-
# after an ambiguous append; inspect repo state and reconcile explicitly.
|
|
41685
|
-
\`\`\`
|
|
41686
|
-
|
|
41687
|
-
**Create collections:**
|
|
41688
|
-
\`\`\`bash
|
|
41689
|
-
wh commit submit --type pair --members Location/a,Location/b --repo org/repo
|
|
41690
|
-
wh assertion create --shape Distance --about pair:Location/a,Location/b --data '{"value":5}' --repo org/repo
|
|
41691
|
-
\`\`\`
|
|
41692
|
-
|
|
41693
|
-
**Modify data:**
|
|
41694
|
-
\`\`\`bash
|
|
41695
|
-
wh thing revise Shape/name --data '{"x":5,"y":3}' -m "update" --repo org/repo
|
|
41696
|
-
wh thing retract Shape/old-item -m "withdrawn" --reason "data feed contaminated" --repo org/repo
|
|
41697
|
-
\`\`\`
|
|
41698
|
-
|
|
41699
|
-
**Query and filter:**
|
|
41700
|
-
\`\`\`bash
|
|
41701
|
-
wh thing query --shape MyShape # by shape
|
|
41702
|
-
wh thing query --kind assertion --about Shape/name # by kind + target
|
|
41703
|
-
wh thing history Shape/name --limit 10 # version history
|
|
41704
|
-
\`\`\`
|
|
41705
|
-
|
|
41706
|
-
## Built-in Content shape
|
|
41707
|
-
|
|
41708
|
-
WarmHub repos expose three well-known content wrefs:
|
|
41709
|
-
- \`Content/Readme\` — stored markdown for humans
|
|
41710
|
-
- \`Content/Agents\` — stored markdown guidance for AI agents
|
|
41711
|
-
- \`Content/LlmsTxt\` — synthesized per-request sitemap (read-only)
|
|
41712
|
-
|
|
41713
|
-
Fetch via \`wh repo content get --kind readme|agents|llms-txt\`,
|
|
41714
|
-
\`client.repo.getReadme/getAgents/getLlmsTxt\`, MCP \`warmhub_repo_content_get\`,
|
|
41715
|
-
or raw HTTP \`GET /{org}/{repo}/readme.md|agents.md|llms.txt\`.
|
|
41716
|
-
See \`wh repo describe\` → \`additionalInformation\` for the discovery field.
|
|
41717
|
-
|
|
41718
|
-
## Query Discipline
|
|
41719
|
-
- Plan the repo, shapes, and wrefs you need before the first query.
|
|
41720
|
-
- Gather the needed facts from one repo before switching to another.
|
|
41721
|
-
- Do the queries first, then write one complete answer.
|
|
41722
|
-
|
|
41723
|
-
## Agent Tips
|
|
41724
|
-
- **Always run commands for live data** — this context describes the CLI, not repo contents
|
|
41725
|
-
- **Before writing, discover wrefs** — run \`wh thing list\` or \`wh shape list\`
|
|
41726
|
-
- **Shape field types**: \`string\`, \`number\`, \`boolean\`, \`wref\`, arrays, optionals, nested objects
|
|
41727
|
-
- **Write commands return per-operation results** — relay failures and affected wrefs to the user
|
|
41728
|
-
- **Pass data inline** with \`--data '{...}'\` — do NOT create temp files
|
|
41729
|
-
- Add \`--json\` to any command for machine-readable JSON output
|
|
41730
|
-
- **Aliases teach canonical commands** — executing aliases emit a status hint; misleading lifecycle aliases reject and point to \`retract\`
|
|
41731
|
-
- Writes go through \`wh commit submit\` (or bare \`wh commit\`) or wrappers (\`create\`, \`revise\`, \`retract\`, \`assertion create\`). \`retract\` irreversibly withdraws an identity and creates a history entry.
|
|
41732
|
-
- Use \`wh doctor\` to check environment health
|
|
41733
|
-
`;
|
|
42482
|
+
var prime_content_default = "# WarmHub CLI Context\n> **Context Recovery**: Run `wh prime` after compaction or new session\n\n## Environment\n{{REPO_LINE}}\n\n## Core Concepts\n- **Thing**: A named entity versioned by writes. **Assertion**: A thing that makes a shape-validated claim about another thing.\n- **Shape**: A thing defining data structure; every other thing has one. **Write**: One or more add/revise/retract operations with per-operation results.\n- **wref**: A reference to a thing. Local: `Player` (the shape) or `Player/alice` (a thing with that shape). Cross-repo: `wh:org/repo/Shape` or `wh:org/repo/Shape/name`.\n\n## Versioned Wrefs\n- `Shape` addresses the shape itself; `Shape/name` addresses a thing with that shape. `@vN` pins either.\n- Floating write refs to retracted targets fail; existing pinned versions remain valid.\n- Rename invalidates old spellings, including `@vN`; the new name resolves history.\n- Untyped wrefs accept any thing. `wref<T>` requires the target's shape to be `T`; a shape has no shape, so never satisfies it. `wref?` coalesces only `thing_absent`, never a missing shape.\n\n## Key Workflows\n\n**Write data** (discover shapes → scaffold ops → submit):\n```bash\nwh shape list --repo org/repo # list available shapes\nwh shape view ShapeName --repo org/repo # inspect fields\nwh shape template ShapeName -o ops.json --repo org/repo # scaffold write ops (supports --kind assertion)\n# edit ops.json — fill FILL_IN placeholders — then:\nwh commit submit --file ops.json -m \"msg\" --repo org/repo # submit operations (bare `wh commit` also works)\n# or single assertion (no file needed):\nwh assertion create --shape ShapeName --about Target/name --name my-assertion --data '{\"field\":1}' --repo org/repo\n# Relay failed operation details when present. Never hand-guess ops JSON — use `wh shape template <Shape>`.\n```\n\n**Read data:**\n```bash\nwh thing list --repo org/repo # all things at HEAD\nwh thing view Shape/name --repo org/repo # inspect a thing\nwh thing query --shape MyShape --repo org/repo # find things by shape\nwh thing about Shape --repo org/repo # assertions about a shape\nwh assertion list --repo org/repo # all assertions at HEAD\nwh thing history Shape/name --repo org/repo # version history\n\n# Batch read — wh thing view is variadic (max 500 wrefs/call):\nwh thing view Player/alice Player/bob # variadic positionals\nwh thing view --file wrefs.txt --json # one wref per line\ncat wrefs.txt | wh thing view --format jsonl # one JSON line per *deduped* requested wref\n```\n\n## Wref Quick Reference\n\nWrites use explicit names and wrefs. Untyped fields, collection members,\nassertion `about`, and committers accept any thing. Create a deterministic\ntarget before referencing it in the same commit.\n\n## Command Reference\n\n**Global flags**: `--repo`, `--format`, `--json`, `--live`\n### thing — Thing operations\n- `wh thing list [--shape] [--kind] [--match] [--include-retracted]` — Current HEAD state\n- `wh thing view [<wref>...] [--file <path>] [--version] [--depth] [--include-retracted] [--data-mode auto|full]` — Thing details. Variadic (max 500). `--version` implies `--include-retracted`. Batch JSON returns `{ requested, items, missing }`; jsonl emits one row per deduped requested wref. Large Set/List bodies summarize by default; use `--data-mode full` for canonical collection JSON.\n- `wh thing history [wref] [--shape] [--about] [--include-retracted]` — Version history\n- `wh thing resolve <wref>` — Resolve a wref to its canonical thing identity\n- `wh thing create <name|Shape/name> --data <json-object> [--shape] [--message] [--committer]` — Create\n- `wh thing revise <name> [--data] [--message] [--committer] [--expected-version]` — Revise (CONFLICT if HEAD≠n)\n- `wh thing retract <wref> -m <message> [--reason] [--kind]` — Retract\n- `wh thing query [--shape] [--kind] [--about] [--match]` — Query by filters\n- `wh thing search <query> [--shape] [--kind] [--about] [--mode]` — Search text\n- `wh thing rename <Shape/oldName> <newName>` — Rename\n- `wh thing refs <wref> [--inbound] [--outbound] [--field]` — Show field references; use `wh thing about` for assertions about the target thing\n- `wh thing about <wref> [--shape] [--match] [--depth] [--resolve-collections] [--limit] [--include-retracted]` — Show assertions about the target identity; `--resolve-collections` expands collection members for bare/@HEAD/@ALL inputs, not pinned @vN\n\n### commit — Write operations\n- `wh commit submit [--ops|--file|--add|--revise|--retract] [--kind] [--data] [--reason] [--expected-version] [--chunk-size] [--skip-existing] [--progress] [--stream-id]` — Submit operations (bare `wh commit` is equivalent). Use `--file ops.jsonl --stream-id <id> --chunk-size 5000 --skip-existing` for bulk ingest.\n- `wh shape template <shape> [shape2 ...] [--kind] [--operation add|revise|retract] [-o file]` — Generate sample ops\n\n### assertion — Assertion operations\n- `wh assertion list [--about wref] [--shape] [--match] [--include-retracted]` — Browse assertions\n- `wh assertion view <wref> [--version] [--include-retracted]` — Assertion details\n- `wh assertion create [--name] [--shape] [--data] [--about] [--message] [--committer]` — Create assertion\n- `wh assertion revise <wref> --data <json> [--message] [--committer]` — Revise assertion\n- `wh assertion retract <wref> -m <message> [--reason] [--committer]` — Retract assertion\n- `wh assertion history <wref> [--include-retracted]` — Assertion history\n\n### shape — Shape management\n- `wh shape list [--match] [--include-retracted]` — List all shapes\n- `wh shape view <name> [--include-retracted]` — Shape details\n- `wh shape revise <name> [--fields]` — Revise shape\n- `wh shape create <name> [--fields]` — Create shape\n- `wh shape retract <name> -m <message> [--reason]` — Retract shape\n- `wh shape history <name> [--include-retracted]` — Shape history\n- `wh shape rename <oldName> <newName>` — Rename shape\n\n### repo — Repository management\n- `wh repo create <org/name> [--display-name] [--description] [--visibility]` — Create repo\n- `wh repo list [org]` — List repos\n- `wh repo view [org/repo]` — Repo details\n\n### org — Organization management\n- `wh org create <name> [--display-name]` — Create a new organization\n- `wh org view <name>` — View organization details (alias: info)\n- `wh org list` — List all organizations\n\n### sub — Subscription management\n- `wh sub create <name> [flags]` — Create a subscription\n- `wh sub view <name>` — View subscription details\n- `wh sub list` — List all subscriptions\n- `wh sub log <name>` — Tail subscription delivery feed\n- `wh sub attempts <runId>` — Show attempt history for a run\n- `wh sub pause <name>` — Pause a subscription\n- `wh sub resume <name>` — Resume a paused subscription\n- `wh sub bind <name> [--credentials]` — Bind a credential set to a subscription for webhook auth\n- `wh sub unbind <name>` — Remove credential binding from a subscription\n- `wh sub delete <name>` — Delete a subscription\n\n### notifications — Action notification listing\n- `wh notifications [--limit] [--since]` — List repo-scoped action notifications\n\n### credential — Credential set management\n- `wh credential create <name> [--repo org/repo | --org org] [--scope] [--description]` — Create an empty credential set\n- `wh credential list [--repo org/repo | --org org]` — List credential sets accessible from a repo or org\n- `wh credential view <name> [--repo org/repo | --org org]` — View a credential set (key names only, no values)\n- `wh credential delete <name> [--repo org/repo | --org org]` — Delete a credential set and its Vault object\n- `wh credential set <setName> [<keyName>] [--repo org/repo | --org org] [--value]` — Set credential key(s). With `<keyName>`: single-key form (reads value from `--value` or stdin). Without `<keyName>`: batch form (reads JSON object from stdin, e.g. `{\"KEY\":\"val\"}`)\n- `wh credential unset <setName> <keyName> [--repo org/repo | --org org]` — Remove a key from a credential set\n- `wh credential audit <setName> [--repo org/repo | --org org]` — View audit log for a credential set\n- `wh credential revoke <setName> [--repo org/repo | --org org] [--reason]` — Revoke a credential set (blocks new binds and strips auth from existing webhook deliveries)\n\n### component — Component management\n- `wh component validate <path>` — Validate package\n- `wh component install <org/name>` — Install a registered component\n- `wh component register <name> --org <org> --manifest <path> [flags]` — Register component identity\n- `wh component unregister <org/name>` — Remove a registered component identity\n- `wh component registry list --org <org>` — List registered components\n- `wh component registry view <org/name>` — View a registered component\n- `wh component registry update <org/name> [flags]` — Update a registered component\n- `wh component list` — List installed components\n- `wh component update <org/name>` — Update installed component\n- `wh component view <org/name>` — Show component details (alias: show)\n- `wh component doctor <org/name>` — Run component health checks\n- `wh component teardown <org/name>` — Pause component subscriptions\n\n### Getting More Info\n- `wh help` — full help overview\n- `wh <domain>` — list verbs for a domain\n- `wh <domain> <verb> --help` — verb details with flags and examples\n- `wh help --format json` — full CLI spec as JSON (best for agents)\n\n## Common Workflows\n\n**Explore a repo:**\n```bash\nwh thing list --repo org/repo # see all things in HEAD\nwh thing view Shape/name --repo org/repo # inspect a specific thing\nwh thing history Shape/name --repo org/repo # inspect version history\nwh thing about Shape/name # assertions about thing/shape\n```\n\n**Create an assertion** (most common write):\n```bash\n# --about takes an untyped target wref: Shape or Shape/name.\nwh assertion create --shape MyShape --about TargetShape/target-name \\\n --name my-assertion --data '{\"field_a\":1,\"field_b\":\"value\"}' --repo org/repo\n# Output includes per-operation status; relay failures when present.\n```\n\n**Create via write entrypoint** (alternative, supports batches and streams):\n```bash\nwh commit submit --add my-item --shape MyShape --kind assertion \\\n --about TargetShape/target-name --data '{\"field_a\":1}' --repo org/repo\n```\n\n**Batch write via file** (generate template → edit → submit):\n```bash\nwh shape template Hypothesis Evidence -o ops.json # add --kind assertion --about TargetShape/name for assertions\n# edit ops.json — fill FILL_IN placeholders\nwh commit submit --file ops.json -m \"batch update\" # submit all operations (bare `wh commit` is equivalent)\n# --file format: docs.warmhub.ai/cli-reference/commit-operations\n```\n\n**Bulk write (JSONL stream, >1k ops)** — one chunked stream beats per-record commits (~60× faster):\n```bash\nwh shape template MyShape -o ops.jsonl # one op per line (.jsonl)\nID=\"bulk-$(date +%s)\" # choose your own; set it up front so reruns are safe\nwh commit submit --file ops.jsonl --stream-id \"$ID\" --chunk-size 5000 \\\n --skip-existing --progress -m \"bulk ingest\" --repo org/repo\n# --chunk-size: ops per append chunk (default 1000, max 10000); chunk≈1 is ~60× slower\n# --skip-existing: skips already-written add ops (drops per-row read-before-write)\n# Add-stream restart: rerun the WHOLE file with the SAME --stream-id.\n# Fixed-name adds are idempotent via --skip-existing. Mid-stream resume is not\n# a CLI mode. Mixed revise/retract JSONL streams are not full-rerun safe after\n# an ambiguous append; inspect repo state and reconcile explicitly.\n```\n\n**Create collections:**\n```bash\nwh commit submit --type pair --name location-distance --members Location,Location/a --repo org/repo\nwh assertion create --shape Distance --about Pair/location-distance --data '{\"value\":5}' --repo org/repo\n```\n\n**Modify data:**\n```bash\nwh thing revise Shape/name --data '{\"x\":5,\"y\":3}' -m \"update\" --repo org/repo\nwh thing retract Shape/old-item -m \"withdrawn\" --reason \"data feed contaminated\" --repo org/repo\n```\n\n**Query and filter:**\n```bash\nwh thing query --shape MyShape # by shape\nwh thing query --kind assertion --about Shape/name # by kind + target\nwh thing history Shape/name --limit 10 # version history\n```\n\n## Built-in Content shape\n\nWarmHub repos expose three well-known content wrefs:\n- `Content/Readme` — stored markdown for humans\n- `Content/Agents` — stored markdown guidance for AI agents\n- `Content/LlmsTxt` — synthesized per-request sitemap (read-only)\n\nFetch via `wh repo content get --kind readme|agents|llms-txt`,\n`client.repo.getReadme/getAgents/getLlmsTxt`, MCP `warmhub_repo_content_get`,\nor raw HTTP `GET /{org}/{repo}/readme.md|agents.md|llms.txt`.\nSee `wh repo describe` → `additionalInformation` for the discovery field.\n\n## Query Discipline\n- Plan the repo, shapes, and wrefs you need before the first query.\n- Gather the needed facts from one repo before switching to another.\n- Do the queries first, then write one complete answer.\n\n## Agent Tips\n- **Always run commands for live data** — this context describes the CLI, not repo contents\n- **Before writing, discover wrefs** — run `wh thing list` or `wh shape list`\n- **Shape field types**: `string`, `number`, `boolean`, `wref`, arrays, optionals, nested objects\n- **Write commands return per-operation results** — relay failures and affected wrefs to the user\n- **Pass data inline** with `--data '{...}'` — do NOT create temp files\n- Add `--json` to any command for machine-readable JSON output\n- **Aliases teach canonical commands** — executing aliases emit a status hint; misleading lifecycle aliases reject and point to `retract`\n- Writes go through `wh commit submit` (or bare `wh commit`) or wrappers (`create`, `revise`, `retract`, `assertion create`). `retract` irreversibly withdraws an identity and creates a history entry.\n- Use `wh doctor` to check environment health\n";
|
|
41734
42483
|
|
|
41735
42484
|
// ../../packages/warmhub-cli/src/domains/prime.ts
|
|
41736
42485
|
function buildMarkdown(config) {
|
|
@@ -41776,9 +42525,8 @@ var wrefSyntax = {
|
|
|
41776
42525
|
"Player/alice",
|
|
41777
42526
|
"GameState/round-1/state"
|
|
41778
42527
|
],
|
|
41779
|
-
canonicalFormat: "wh:org/repo/Shape/name",
|
|
41780
|
-
versionModifiers: ["@HEAD", "@vN", "@ALL"]
|
|
41781
|
-
batchTokens: { allocate: "$N", reference: "#N" }
|
|
42528
|
+
canonicalFormat: "wh:org/repo/Shape or wh:org/repo/Shape/name",
|
|
42529
|
+
versionModifiers: ["@HEAD", "@vN", "@ALL"]
|
|
41782
42530
|
};
|
|
41783
42531
|
var handlePrime = async (ctx) => {
|
|
41784
42532
|
writeOutput(ctx, {
|
|
@@ -42886,7 +43634,7 @@ var retractFlags3 = {
|
|
|
42886
43634
|
reason: flag.string({ description: "Reason for retraction (<=500 chars)" }),
|
|
42887
43635
|
message: flag.string({ short: "m", description: "Commit message" }),
|
|
42888
43636
|
committer: flag.string({
|
|
42889
|
-
description: "Committer
|
|
43637
|
+
description: "Committer wref (shape or shaped thing; e.g. Agent/bot-1)"
|
|
42890
43638
|
})
|
|
42891
43639
|
};
|
|
42892
43640
|
var handleCreate6 = async (ctx, { flags, args }) => {
|
|
@@ -43062,7 +43810,7 @@ var createFlags8 = {
|
|
|
43062
43810
|
description: "Shape to subscribe to"
|
|
43063
43811
|
}),
|
|
43064
43812
|
event: flag.string({
|
|
43065
|
-
description: "Event to watch: commit (default), repo.renamed, or
|
|
43813
|
+
description: "Event to watch: commit (default), repo.renamed, org.renamed, thing.renamed, or shape.renamed"
|
|
43066
43814
|
}),
|
|
43067
43815
|
org: flag.string({
|
|
43068
43816
|
description: "Org slug for an org-scoped subscription (org.renamed)"
|
|
@@ -43259,7 +44007,7 @@ function scopeLabel(scope) {
|
|
|
43259
44007
|
// ../../packages/warmhub-cli/src/domains/sub/handlers-create.ts
|
|
43260
44008
|
var handleCreate7 = async (ctx, { flags, args }) => {
|
|
43261
44009
|
const name = args[0] ?? flags.name;
|
|
43262
|
-
const usage = "Usage: wh sub create <name> (--repo org/repo | --org org) [--event commit|repo.renamed|org.renamed] [options]";
|
|
44010
|
+
const usage = "Usage: wh sub create <name> (--repo org/repo | --org org) [--event commit|repo.renamed|org.renamed|thing.renamed|shape.renamed] [options]";
|
|
43263
44011
|
const example = `wh sub create signal-hook --repo myorg/myrepo --on Signal --filter '{"shape":"Signal"}' --webhook-url https://example.com/hook`;
|
|
43264
44012
|
if (!name) {
|
|
43265
44013
|
usageError(usage, example);
|
|
@@ -43298,7 +44046,7 @@ var handleCreate7 = async (ctx, { flags, args }) => {
|
|
|
43298
44046
|
return;
|
|
43299
44047
|
}
|
|
43300
44048
|
const { org, repo } = resolveRepoContext(ctx);
|
|
43301
|
-
if (eventType
|
|
44049
|
+
if (eventType !== "commit") {
|
|
43302
44050
|
rejectCommitFlags(flags, eventType);
|
|
43303
44051
|
const result2 = await ctx.client.subscription.create({
|
|
43304
44052
|
orgName: org,
|
|
@@ -43311,7 +44059,7 @@ var handleCreate7 = async (ctx, { flags, args }) => {
|
|
|
43311
44059
|
});
|
|
43312
44060
|
writeOutput(ctx, result2, () => {
|
|
43313
44061
|
const c = ctx.colors;
|
|
43314
|
-
ctx.status(`${c.green}Created subscription${c.reset} ${c.cyan}${name}${c.reset} on ${c.cyan}${org}/${repo}${c.reset} (
|
|
44062
|
+
ctx.status(`${c.green}Created subscription${c.reset} ${c.cyan}${name}${c.reset} on ${c.cyan}${org}/${repo}${c.reset} (${eventType})`);
|
|
43315
44063
|
});
|
|
43316
44064
|
return;
|
|
43317
44065
|
}
|
|
@@ -44102,7 +44850,7 @@ var TOKEN_DOMAIN = defineDomain({
|
|
|
44102
44850
|
});
|
|
44103
44851
|
|
|
44104
44852
|
// ../../packages/warmhub-cli/src/update-check-cache.ts
|
|
44105
|
-
import { mkdirSync as mkdirSync7, readFileSync as
|
|
44853
|
+
import { mkdirSync as mkdirSync7, readFileSync as readFileSync10, writeFileSync as writeFileSync7 } from "node:fs";
|
|
44106
44854
|
import { homedir as homedir5 } from "node:os";
|
|
44107
44855
|
import { dirname as dirname7, resolve as resolve3 } from "node:path";
|
|
44108
44856
|
|
|
@@ -44171,7 +44919,7 @@ var WH_CACHE_PACKAGE_NAME = WH_CLI_PACKAGE_NAME;
|
|
|
44171
44919
|
var cachePath = (homePath) => resolve3(homePath, ".warmhub", "cli", "update-check.json");
|
|
44172
44920
|
var readCache = (homePath) => {
|
|
44173
44921
|
try {
|
|
44174
|
-
return JSON.parse(
|
|
44922
|
+
return JSON.parse(readFileSync10(cachePath(homePath), "utf8"));
|
|
44175
44923
|
} catch {
|
|
44176
44924
|
return;
|
|
44177
44925
|
}
|
|
@@ -44195,7 +44943,7 @@ var markUpdateNoticeShown = ({
|
|
|
44195
44943
|
|
|
44196
44944
|
// ../../packages/warmhub-cli/src/domains/update-install.ts
|
|
44197
44945
|
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
44198
|
-
import { existsSync as existsSync9, readFileSync as
|
|
44946
|
+
import { existsSync as existsSync9, readFileSync as readFileSync11, realpathSync } from "node:fs";
|
|
44199
44947
|
import { homedir as homedir6 } from "node:os";
|
|
44200
44948
|
import { dirname as dirname8, resolve as resolve4 } from "node:path";
|
|
44201
44949
|
var DEV_INSTALL_PACKAGE_SEARCH_DEPTH = 8;
|
|
@@ -44345,7 +45093,7 @@ var isDevInstall = (scriptPath) => {
|
|
|
44345
45093
|
for (let i = 0;i < DEV_INSTALL_PACKAGE_SEARCH_DEPTH; i += 1) {
|
|
44346
45094
|
const pkgPath = resolve4(dir, "package.json");
|
|
44347
45095
|
try {
|
|
44348
|
-
const pkg = JSON.parse(
|
|
45096
|
+
const pkg = JSON.parse(readFileSync11(pkgPath, "utf8"));
|
|
44349
45097
|
if (pkg.name === "@warmhub/cli") {
|
|
44350
45098
|
if (pkg.private === true)
|
|
44351
45099
|
return true;
|
|
@@ -44631,6 +45379,7 @@ function registerAllDomains(registry2) {
|
|
|
44631
45379
|
registry2.register(INIT_DOMAIN);
|
|
44632
45380
|
registry2.register(REPO_DOMAIN);
|
|
44633
45381
|
registry2.register(THING_DOMAIN);
|
|
45382
|
+
registry2.register(COLLECTION_DOMAIN);
|
|
44634
45383
|
registry2.register(COMMIT_DOMAIN);
|
|
44635
45384
|
registry2.register(ASSERTION_DOMAIN);
|
|
44636
45385
|
registry2.register(SHAPE_DOMAIN);
|
|
@@ -45753,7 +46502,7 @@ function resolveLogLevel(flags, env) {
|
|
|
45753
46502
|
// package.json
|
|
45754
46503
|
var package_default3 = {
|
|
45755
46504
|
name: "@warmhub/cli",
|
|
45756
|
-
version: "0.
|
|
46505
|
+
version: "0.69.0",
|
|
45757
46506
|
private: false,
|
|
45758
46507
|
type: "module",
|
|
45759
46508
|
description: "The wh CLI for WarmHub — create repos, commit and query data, and compound knowledge with your AI agents.",
|
|
@@ -46408,4 +47157,4 @@ if (!updateCheckSuppressedByArgv && shouldRunUpdateCheck(updateEligibility)) {
|
|
|
46408
47157
|
var interceptedExitCode = await maybeHandleComponentShellBoundary(dispatchArgv);
|
|
46409
47158
|
process.exitCode = interceptedExitCode === undefined ? await runCli(dispatchArgv, { version: package_default3.version }) : interceptedExitCode;
|
|
46410
47159
|
|
|
46411
|
-
//# debugId=
|
|
47160
|
+
//# debugId=C8123553A9E5F6D464756E2164756E21
|