@warmhub/cli 0.67.0 → 0.68.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 +1199 -254
- 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)
|
|
@@ -19949,9 +19922,99 @@ var PLATFORM_STATUS_PROBE_ARTIFACT_FIELDS = {
|
|
|
19949
19922
|
description: "Optional URL associated with this artifact."
|
|
19950
19923
|
}
|
|
19951
19924
|
};
|
|
19925
|
+
// ../../packages/rules/src/tokens.ts
|
|
19926
|
+
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.";
|
|
19927
|
+
var ANY_TOKEN_RE = /[$#]\d+/;
|
|
19928
|
+
function hasAnyTokens(s) {
|
|
19929
|
+
return ANY_TOKEN_RE.test(s);
|
|
19930
|
+
}
|
|
19931
|
+
|
|
19932
|
+
// ../../packages/rules/src/preflight-commit.ts
|
|
19933
|
+
function preflightCommitDiagnostics(operations, options) {
|
|
19934
|
+
const errors = [];
|
|
19935
|
+
rejectCommitTokenSyntax(operations, errors);
|
|
19936
|
+
illegalOpSequences(operations, errors, options?.checkAddAdd ?? true);
|
|
19937
|
+
return errors;
|
|
19938
|
+
}
|
|
19939
|
+
function getOpName(op) {
|
|
19940
|
+
return op.name;
|
|
19941
|
+
}
|
|
19942
|
+
function tokenStringFields(op) {
|
|
19943
|
+
const fields = [getOpName(op), op.newName];
|
|
19944
|
+
if (typeof op.about === "string") {
|
|
19945
|
+
fields.push(op.about);
|
|
19946
|
+
}
|
|
19947
|
+
if (op.members) {
|
|
19948
|
+
fields.push(...op.members);
|
|
19949
|
+
}
|
|
19950
|
+
return fields;
|
|
19951
|
+
}
|
|
19952
|
+
function rejectCommitTokenSyntax(operations, errors) {
|
|
19953
|
+
for (let i = 0;i < operations.length; i++) {
|
|
19954
|
+
const op = operations[i];
|
|
19955
|
+
if (!op)
|
|
19956
|
+
continue;
|
|
19957
|
+
for (const field of tokenStringFields(op)) {
|
|
19958
|
+
if (field && hasAnyTokens(field)) {
|
|
19959
|
+
errors.push({
|
|
19960
|
+
code: "COMMIT_TOKEN_SYNTAX_REMOVED",
|
|
19961
|
+
operationIndex: i,
|
|
19962
|
+
message: COMMIT_TOKEN_SYNTAX_REMOVED_MESSAGE
|
|
19963
|
+
});
|
|
19964
|
+
break;
|
|
19965
|
+
}
|
|
19966
|
+
}
|
|
19967
|
+
}
|
|
19968
|
+
}
|
|
19969
|
+
function illegalOpSequences(operations, errors, checkAddAdd) {
|
|
19970
|
+
const opHistory = new Map;
|
|
19971
|
+
for (let i = 0;i < operations.length; i++) {
|
|
19972
|
+
const op = operations[i];
|
|
19973
|
+
if (!op)
|
|
19974
|
+
continue;
|
|
19975
|
+
const name = getOpName(op);
|
|
19976
|
+
if (!name)
|
|
19977
|
+
continue;
|
|
19978
|
+
if (hasAnyTokens(name))
|
|
19979
|
+
continue;
|
|
19980
|
+
const kind = inferOperationKind({ ...op, name });
|
|
19981
|
+
const qualName = kind === "shape" ? `shape:${name}` : `thing:${name}`;
|
|
19982
|
+
const history = opHistory.get(qualName) ?? [];
|
|
19983
|
+
history.push({ operation: op.operation, index: i });
|
|
19984
|
+
opHistory.set(qualName, history);
|
|
19985
|
+
}
|
|
19986
|
+
for (const [qualName, history] of opHistory) {
|
|
19987
|
+
if (history.length < 2)
|
|
19988
|
+
continue;
|
|
19989
|
+
for (let i = 1;i < history.length; i++) {
|
|
19990
|
+
const prev = history[i - 1];
|
|
19991
|
+
const curr = history[i];
|
|
19992
|
+
if (!prev || !curr)
|
|
19993
|
+
continue;
|
|
19994
|
+
const pair = `${prev.operation}+${curr.operation}`;
|
|
19995
|
+
if (checkAddAdd && pair === "add+add") {
|
|
19996
|
+
errors.push({
|
|
19997
|
+
code: "ILLEGAL_OP_SEQUENCE",
|
|
19998
|
+
operationIndex: curr.index,
|
|
19999
|
+
message: `Cannot add "${qualName}" twice in the same commit`
|
|
20000
|
+
});
|
|
20001
|
+
}
|
|
20002
|
+
if (pair === "revise+add") {
|
|
20003
|
+
errors.push({
|
|
20004
|
+
code: "ILLEGAL_OP_SEQUENCE",
|
|
20005
|
+
operationIndex: curr.index,
|
|
20006
|
+
message: `Cannot revise then add "${qualName}" in the same commit`
|
|
20007
|
+
});
|
|
20008
|
+
}
|
|
20009
|
+
}
|
|
20010
|
+
}
|
|
20011
|
+
}
|
|
20012
|
+
|
|
19952
20013
|
// ../../packages/rules/src/preflight-operation.ts
|
|
19953
|
-
var collectionTypes = ["pair", "
|
|
20014
|
+
var collectionTypes = ["pair", "set", "list"];
|
|
19954
20015
|
var collectionOps = ["add", "revise"];
|
|
20016
|
+
var COLLECTION_CREATE_REQUIRES_NAME_MESSAGE = "Collection create requires a name. Collections are ordinary named things (ADR 0004).";
|
|
20017
|
+
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
20018
|
function preflightOpDiagnostics(op, operationIndex) {
|
|
19956
20019
|
const errors = [];
|
|
19957
20020
|
errors.push(...builtinShapeGuard(op, operationIndex));
|
|
@@ -19964,17 +20027,36 @@ function preflightOpDiagnostics(op, operationIndex) {
|
|
|
19964
20027
|
function builtinShapeGuard(op, operationIndex) {
|
|
19965
20028
|
const errors = [];
|
|
19966
20029
|
const name = op.name;
|
|
19967
|
-
if (
|
|
20030
|
+
if (name && isRetiredCollectionShape(name)) {
|
|
20031
|
+
errors.push({
|
|
20032
|
+
code: "RESERVED_NAME",
|
|
20033
|
+
operationIndex,
|
|
20034
|
+
message: `Shape "${name}" is a retired collection shape and cannot be written manually`
|
|
20035
|
+
});
|
|
20036
|
+
}
|
|
20037
|
+
if (op.operation === "rename" && (op.kind === "shape" || op.name !== undefined && !splitLocalPath(op.name)) && op.newName && isRetiredCollectionShape(op.newName)) {
|
|
20038
|
+
errors.push({
|
|
20039
|
+
code: "RESERVED_NAME",
|
|
20040
|
+
operationIndex,
|
|
20041
|
+
message: `Shape "${op.newName}" is a retired collection shape and cannot be written manually`
|
|
20042
|
+
});
|
|
20043
|
+
} else if (op.operation !== "retract" && op.kind === "shape" && name && isBuiltinShape(name)) {
|
|
19968
20044
|
errors.push({
|
|
19969
20045
|
code: "RESERVED_NAME",
|
|
19970
20046
|
operationIndex,
|
|
19971
20047
|
message: `Shape "${name}" is a built-in shape and cannot be ${op.operation === "add" ? "created" : "revised"} manually`
|
|
19972
20048
|
});
|
|
19973
20049
|
}
|
|
19974
|
-
if (
|
|
20050
|
+
if (name) {
|
|
19975
20051
|
const local = splitLocalPath(name);
|
|
19976
|
-
if (local &&
|
|
19977
|
-
|
|
20052
|
+
if (local && isRetiredCollectionShape(local.shapePrefix)) {
|
|
20053
|
+
errors.push({
|
|
20054
|
+
code: "VALIDATION_ERROR",
|
|
20055
|
+
operationIndex,
|
|
20056
|
+
message: `Cannot ${op.operation} under retired collection shape "${local.shapePrefix}". Triple is read-only and retired for new collection writes.`
|
|
20057
|
+
});
|
|
20058
|
+
} else if (op.kind === "thing" && local && isBuiltinCollectionShape(local.shapePrefix)) {
|
|
20059
|
+
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
20060
|
errors.push({
|
|
19979
20061
|
code: "VALIDATION_ERROR",
|
|
19980
20062
|
operationIndex,
|
|
@@ -20014,16 +20096,32 @@ function contentNameGuard(op, operationIndex) {
|
|
|
20014
20096
|
function plusSignGuard(op, operationIndex) {
|
|
20015
20097
|
const errors = [];
|
|
20016
20098
|
const name = op.name;
|
|
20017
|
-
if (op.
|
|
20099
|
+
if (op.newName?.includes("+")) {
|
|
20100
|
+
errors.push({
|
|
20101
|
+
code: "VALIDATION_ERROR",
|
|
20102
|
+
operationIndex,
|
|
20103
|
+
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.`
|
|
20104
|
+
});
|
|
20018
20105
|
return errors;
|
|
20106
|
+
}
|
|
20019
20107
|
if (name?.includes("+")) {
|
|
20108
|
+
if (op.kind === "collection" && op.operation === "add") {
|
|
20109
|
+
errors.push({
|
|
20110
|
+
code: "VALIDATION_ERROR",
|
|
20111
|
+
operationIndex,
|
|
20112
|
+
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.`
|
|
20113
|
+
});
|
|
20114
|
+
return errors;
|
|
20115
|
+
}
|
|
20116
|
+
if (op.kind === "collection")
|
|
20117
|
+
return errors;
|
|
20020
20118
|
const local = splitLocalPath(name);
|
|
20021
|
-
if (local &&
|
|
20119
|
+
if (local && isReservedCollectionShape(local.shapePrefix))
|
|
20022
20120
|
return errors;
|
|
20023
20121
|
errors.push({
|
|
20024
20122
|
code: "VALIDATION_ERROR",
|
|
20025
20123
|
operationIndex,
|
|
20026
|
-
message: `Name "${name}" contains reserved character "+". The "+" character is reserved for collection names.`
|
|
20124
|
+
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
20125
|
});
|
|
20028
20126
|
}
|
|
20029
20127
|
return errors;
|
|
@@ -20032,102 +20130,79 @@ function validateCollectionAbouts(op, operationIndex) {
|
|
|
20032
20130
|
const errors = [];
|
|
20033
20131
|
if (!op.about || typeof op.about === "string")
|
|
20034
20132
|
return errors;
|
|
20035
|
-
|
|
20036
|
-
|
|
20133
|
+
errors.push({
|
|
20134
|
+
code: "VALIDATION_ERROR",
|
|
20135
|
+
operationIndex,
|
|
20136
|
+
message: COLLECTION_ABOUT_REMOVED_MESSAGE
|
|
20137
|
+
});
|
|
20138
|
+
return errors;
|
|
20139
|
+
}
|
|
20140
|
+
function validateCollectionOps(op, operationIndex) {
|
|
20141
|
+
const errors = [];
|
|
20142
|
+
if (op.kind !== "collection")
|
|
20143
|
+
return errors;
|
|
20144
|
+
if (!collectionOps.includes(op.operation)) {
|
|
20145
|
+
return errors;
|
|
20146
|
+
}
|
|
20147
|
+
if (op.operation === "add" && !op.name) {
|
|
20037
20148
|
errors.push({
|
|
20038
20149
|
code: "VALIDATION_ERROR",
|
|
20039
20150
|
operationIndex,
|
|
20040
|
-
message:
|
|
20151
|
+
message: COLLECTION_CREATE_REQUIRES_NAME_MESSAGE
|
|
20041
20152
|
});
|
|
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
20153
|
}
|
|
20055
|
-
|
|
20056
|
-
if (arityError) {
|
|
20154
|
+
if (!op.type || !collectionTypes.includes(op.type)) {
|
|
20057
20155
|
errors.push({
|
|
20058
20156
|
code: "VALIDATION_ERROR",
|
|
20059
20157
|
operationIndex,
|
|
20060
|
-
message:
|
|
20158
|
+
message: `Collection "type" must be one of: pair, set, list. Got: "${op.type ?? ""}"`
|
|
20061
20159
|
});
|
|
20062
20160
|
}
|
|
20063
|
-
|
|
20064
|
-
}
|
|
20065
|
-
function validateCollectionOps(op, operationIndex) {
|
|
20066
|
-
const errors = [];
|
|
20067
|
-
if (op.kind !== "collection")
|
|
20068
|
-
return errors;
|
|
20069
|
-
if (!collectionOps.includes(op.operation)) {
|
|
20161
|
+
if (!op.members || !Array.isArray(op.members)) {
|
|
20070
20162
|
errors.push({
|
|
20071
20163
|
code: "VALIDATION_ERROR",
|
|
20072
20164
|
operationIndex,
|
|
20073
|
-
message:
|
|
20165
|
+
message: 'Collection requires a "members" array'
|
|
20074
20166
|
});
|
|
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) {
|
|
20167
|
+
} else {
|
|
20168
|
+
for (let i = 0;i < op.members.length; i++) {
|
|
20169
|
+
if (typeof op.members[i] !== "string") {
|
|
20105
20170
|
errors.push({
|
|
20106
20171
|
code: "VALIDATION_ERROR",
|
|
20107
20172
|
operationIndex,
|
|
20108
|
-
message:
|
|
20173
|
+
message: `Collection member at index ${i} must be a string`
|
|
20109
20174
|
});
|
|
20110
20175
|
}
|
|
20111
20176
|
}
|
|
20112
20177
|
}
|
|
20178
|
+
if (op.type && op.members) {
|
|
20179
|
+
const arityError = collectionArityError(op.type, op.members);
|
|
20180
|
+
if (arityError) {
|
|
20181
|
+
errors.push({
|
|
20182
|
+
code: "VALIDATION_ERROR",
|
|
20183
|
+
operationIndex,
|
|
20184
|
+
message: arityError
|
|
20185
|
+
});
|
|
20186
|
+
}
|
|
20187
|
+
}
|
|
20113
20188
|
return errors;
|
|
20114
20189
|
}
|
|
20115
20190
|
function collectionArityError(tag, members) {
|
|
20116
20191
|
switch (tag) {
|
|
20117
20192
|
case "pair":
|
|
20118
20193
|
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
20194
|
case "set":
|
|
20122
20195
|
case "list":
|
|
20123
20196
|
return members.length < 1 ? `${tag === "set" ? "Set" : "List"} requires at least 1 member, got 0` : null;
|
|
20124
20197
|
}
|
|
20125
20198
|
}
|
|
20126
|
-
|
|
20127
20199
|
// ../../packages/rules/src/preflight.ts
|
|
20128
20200
|
function preflightOpDiagnostics2(op, operationIndex) {
|
|
20129
20201
|
return preflightOpDiagnostics(op, operationIndex);
|
|
20130
20202
|
}
|
|
20203
|
+
function preflightCommitDiagnostics2(operations, options) {
|
|
20204
|
+
return preflightCommitDiagnostics(operations, options);
|
|
20205
|
+
}
|
|
20131
20206
|
// ../../packages/rules/src/reserved-orgs.ts
|
|
20132
20207
|
var RESERVED_RAW_CONTENT_TOP_LEVEL_NAMES = [
|
|
20133
20208
|
"_app",
|
|
@@ -27352,7 +27427,7 @@ function findSystemComponent(componentId) {
|
|
|
27352
27427
|
// ../../packages/sdk-ts/package.json
|
|
27353
27428
|
var package_default = {
|
|
27354
27429
|
name: "@warmhub/sdk-ts",
|
|
27355
|
-
version: "0.
|
|
27430
|
+
version: "0.67.0",
|
|
27356
27431
|
private: false,
|
|
27357
27432
|
type: "module",
|
|
27358
27433
|
description: "The TypeScript SDK for WarmHub — create repos, commit and query data, and compound knowledge with your AI agents.",
|
|
@@ -27460,16 +27535,38 @@ function shapeDefinitionPreflightError(name, data, verb) {
|
|
|
27460
27535
|
}
|
|
27461
27536
|
|
|
27462
27537
|
// ../../packages/sdk-ts/src/collection-operation-normalize.ts
|
|
27463
|
-
var collectionTypes2 = new Set([
|
|
27464
|
-
"pair",
|
|
27465
|
-
"triple",
|
|
27466
|
-
"set",
|
|
27467
|
-
"list"
|
|
27468
|
-
]);
|
|
27538
|
+
var collectionTypes2 = new Set(["pair", "set", "list"]);
|
|
27469
27539
|
function normalizeBackendCollectionAdd(operation, source) {
|
|
27470
|
-
const
|
|
27540
|
+
const normalized = normalizeCollectionWrite(operation, source, "add");
|
|
27541
|
+
return {
|
|
27471
27542
|
operation: "add",
|
|
27472
27543
|
kind: "collection",
|
|
27544
|
+
name: normalized.name,
|
|
27545
|
+
type: normalized.type,
|
|
27546
|
+
members: normalized.members,
|
|
27547
|
+
...operation.skipExisting === true ? { skipExisting: true } : {}
|
|
27548
|
+
};
|
|
27549
|
+
}
|
|
27550
|
+
function normalizeBackendCollectionRevise(operation, source) {
|
|
27551
|
+
const normalized = normalizeCollectionWrite(operation, source, "revise");
|
|
27552
|
+
if (!normalized.name) {
|
|
27553
|
+
throw new Error(`${source}: collection revise requires a target name`);
|
|
27554
|
+
}
|
|
27555
|
+
return {
|
|
27556
|
+
operation: "revise",
|
|
27557
|
+
kind: "collection",
|
|
27558
|
+
name: normalized.name,
|
|
27559
|
+
type: normalized.type,
|
|
27560
|
+
members: normalized.members,
|
|
27561
|
+
...typeof operation.expectedVersion === "number" ? { expectedVersion: operation.expectedVersion } : {},
|
|
27562
|
+
...typeof operation.leaseId === "string" && operation.leaseId.length > 0 ? { leaseId: operation.leaseId } : {}
|
|
27563
|
+
};
|
|
27564
|
+
}
|
|
27565
|
+
function normalizeCollectionWrite(operation, source, writeOperation) {
|
|
27566
|
+
const diagnostics = preflightOpDiagnostics2({
|
|
27567
|
+
operation: writeOperation,
|
|
27568
|
+
kind: "collection",
|
|
27569
|
+
name: typeof operation.name === "string" ? operation.name : undefined,
|
|
27473
27570
|
type: typeof operation.type === "string" ? operation.type : undefined,
|
|
27474
27571
|
members: Array.isArray(operation.members) ? operation.members : undefined
|
|
27475
27572
|
}, 0);
|
|
@@ -27478,29 +27575,32 @@ function normalizeBackendCollectionAdd(operation, source) {
|
|
|
27478
27575
|
}
|
|
27479
27576
|
const type = normalizeCollectionType(operation.type);
|
|
27480
27577
|
if (!type) {
|
|
27481
|
-
throw new Error(`${source}: collection
|
|
27578
|
+
throw new Error(`${source}: collection ${writeOperation} requires 'type' to be one of: pair, set, list`);
|
|
27482
27579
|
}
|
|
27483
27580
|
if (!Array.isArray(operation.members)) {
|
|
27484
|
-
throw new Error(`${source}: collection
|
|
27581
|
+
throw new Error(`${source}: collection ${writeOperation} requires a 'members' array`);
|
|
27485
27582
|
}
|
|
27486
27583
|
const name = normalizeOptionalName(operation.name);
|
|
27487
|
-
if (
|
|
27488
|
-
throw new Error(`${source}: collection
|
|
27584
|
+
if (!name) {
|
|
27585
|
+
throw new Error(`${source}: collection ${writeOperation} name must be a non-empty string`);
|
|
27489
27586
|
}
|
|
27490
|
-
|
|
27587
|
+
assertNoUnsupportedCollectionFields(operation, source, writeOperation);
|
|
27491
27588
|
return {
|
|
27492
|
-
|
|
27493
|
-
kind: "collection",
|
|
27494
|
-
...name ? { name } : {},
|
|
27589
|
+
name,
|
|
27495
27590
|
type,
|
|
27496
|
-
members: operation.members
|
|
27497
|
-
...operation.skipExisting === true ? { skipExisting: true } : {}
|
|
27591
|
+
members: operation.members
|
|
27498
27592
|
};
|
|
27499
27593
|
}
|
|
27500
|
-
function
|
|
27501
|
-
const unsupportedFields = [
|
|
27594
|
+
function assertNoUnsupportedCollectionFields(operation, source, writeOperation) {
|
|
27595
|
+
const unsupportedFields = [
|
|
27596
|
+
"about",
|
|
27597
|
+
"aboutWref",
|
|
27598
|
+
"shapeWref",
|
|
27599
|
+
"data",
|
|
27600
|
+
...writeOperation === "revise" ? ["skipExisting"] : []
|
|
27601
|
+
].filter((field) => operation[field] !== undefined);
|
|
27502
27602
|
if (unsupportedFields.length > 0) {
|
|
27503
|
-
throw new Error(`${source}: collection
|
|
27603
|
+
throw new Error(`${source}: collection ${writeOperation} does not support ${unsupportedFields.map((field) => `'${field}'`).join(", ")}`);
|
|
27504
27604
|
}
|
|
27505
27605
|
}
|
|
27506
27606
|
function normalizeCollectionType(value) {
|
|
@@ -27550,12 +27650,12 @@ function toBackendStreamOperation(operation) {
|
|
|
27550
27650
|
if (Object.hasOwn(operation, "active")) {
|
|
27551
27651
|
throw new Error(`${kind2} revise operation no longer supports 'active' — use retract('${name}') instead`);
|
|
27552
27652
|
}
|
|
27653
|
+
if (kind2 === "collection") {
|
|
27654
|
+
return normalizeBackendCollectionRevise(operation, "commit.apply");
|
|
27655
|
+
}
|
|
27553
27656
|
if (operation.data === undefined) {
|
|
27554
27657
|
throw new Error(`${kind2} revise operation requires 'data'`);
|
|
27555
27658
|
}
|
|
27556
|
-
if (kind2 === "collection") {
|
|
27557
|
-
throw new Error(`collection revise is no longer supported — use retract('${name}') instead`);
|
|
27558
|
-
}
|
|
27559
27659
|
if (kind2 === "assertion") {
|
|
27560
27660
|
return {
|
|
27561
27661
|
operation: "revise",
|
|
@@ -27590,6 +27690,9 @@ function toBackendStreamOperation(operation) {
|
|
|
27590
27690
|
if (!("about" in operation) || operation.about === undefined) {
|
|
27591
27691
|
throw new Error("assertion add operation requires 'about'");
|
|
27592
27692
|
}
|
|
27693
|
+
if (typeof operation.about !== "string") {
|
|
27694
|
+
throw new Error(COLLECTION_ABOUT_REMOVED_MESSAGE);
|
|
27695
|
+
}
|
|
27593
27696
|
if (operation.data === undefined) {
|
|
27594
27697
|
throw new Error("assertion add operation requires 'data'");
|
|
27595
27698
|
}
|
|
@@ -27782,34 +27885,14 @@ function computeBackoffDelayMs(attempt, policy) {
|
|
|
27782
27885
|
function sleep2(ms) {
|
|
27783
27886
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
27784
27887
|
}
|
|
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
27888
|
|
|
27807
27889
|
// ../../packages/sdk-ts/src/stream-submit-submit.ts
|
|
27808
27890
|
class StreamValidationError extends Error {
|
|
27809
|
-
code
|
|
27891
|
+
code;
|
|
27810
27892
|
status = 400;
|
|
27811
|
-
constructor(message) {
|
|
27893
|
+
constructor(message, code = "VALIDATION_ERROR") {
|
|
27812
27894
|
super(message);
|
|
27895
|
+
this.code = code;
|
|
27813
27896
|
this.name = "WarmHubError";
|
|
27814
27897
|
}
|
|
27815
27898
|
}
|
|
@@ -27830,6 +27913,7 @@ async function submitOperationsViaStream(client, args) {
|
|
|
27830
27913
|
}
|
|
27831
27914
|
return streamOperation;
|
|
27832
27915
|
});
|
|
27916
|
+
validateNormalizedOperations(operations);
|
|
27833
27917
|
const chunkSize = normalizeChunkSize(args.chunkSize);
|
|
27834
27918
|
let streamId = args.streamId ?? createStreamId();
|
|
27835
27919
|
const policy = args.streamId !== undefined ? false : resolveRetryPolicy(args.retry);
|
|
@@ -27841,7 +27925,6 @@ async function submitOperationsViaStream(client, args) {
|
|
|
27841
27925
|
let attempt = 1;
|
|
27842
27926
|
let priorAttemptAmbiguous = false;
|
|
27843
27927
|
const chunkIsAtomic = chunk.length === 1;
|
|
27844
|
-
const chunkUsesTokens = chunk.some(opUsesTokens);
|
|
27845
27928
|
while (true) {
|
|
27846
27929
|
try {
|
|
27847
27930
|
const appendResult = await client.stream.append({
|
|
@@ -27864,7 +27947,7 @@ async function submitOperationsViaStream(client, args) {
|
|
|
27864
27947
|
if (chunkResults.length === 0 && !priorAttemptAmbiguous && isDefiniteClientError(cause)) {
|
|
27865
27948
|
throw cause;
|
|
27866
27949
|
}
|
|
27867
|
-
if (chunkResults.length === 0 && chunkIsAtomic &&
|
|
27950
|
+
if (chunkResults.length === 0 && chunkIsAtomic && policy !== false && attempt < policy.maxAttempts && isTransientStreamFailure(cause)) {
|
|
27868
27951
|
await sleep2(computeBackoffDelayMs(attempt, policy));
|
|
27869
27952
|
attempt += 1;
|
|
27870
27953
|
priorAttemptAmbiguous = true;
|
|
@@ -27898,6 +27981,16 @@ async function submitOperationsViaStream(client, args) {
|
|
|
27898
27981
|
}
|
|
27899
27982
|
return result;
|
|
27900
27983
|
}
|
|
27984
|
+
function validateNormalizedOperations(operations) {
|
|
27985
|
+
const diagnostics = preflightCommitDiagnostics2(operations).filter((diagnostic) => !isServerAuthoritativeSequenceDiagnostic(diagnostic));
|
|
27986
|
+
const firstDiagnostic = diagnostics[0];
|
|
27987
|
+
if (!firstDiagnostic)
|
|
27988
|
+
return;
|
|
27989
|
+
throw new StreamValidationError(`Invalid operation at index ${firstDiagnostic.operationIndex}: ${firstDiagnostic.message}`, firstDiagnostic.code);
|
|
27990
|
+
}
|
|
27991
|
+
function isServerAuthoritativeSequenceDiagnostic(diagnostic) {
|
|
27992
|
+
return diagnostic.code === "ILLEGAL_OP_SEQUENCE" && diagnostic.message.includes("Cannot revise then add ");
|
|
27993
|
+
}
|
|
27901
27994
|
function isAllSubmittedOperationsFailed(result, submittedOperationCount) {
|
|
27902
27995
|
if (submittedOperationCount <= 0) {
|
|
27903
27996
|
return false;
|
|
@@ -28098,6 +28191,35 @@ function sanitizeSubscriptionUpdateInput(input) {
|
|
|
28098
28191
|
} = input;
|
|
28099
28192
|
return supported;
|
|
28100
28193
|
}
|
|
28194
|
+
function hasCollectionQuerySource(source) {
|
|
28195
|
+
return !!source && (!!source.shape || !!source.kind || !!source.about || !!source.match || !!source.componentRef || source.excludeComponents === true || (source.where?.length ?? 0) > 0);
|
|
28196
|
+
}
|
|
28197
|
+
function hasCollectionSelectorAnchor(source) {
|
|
28198
|
+
return !!source && (!!source.shape || !!source.about || !!source.match || !!source.componentRef || (source.where?.length ?? 0) > 0);
|
|
28199
|
+
}
|
|
28200
|
+
function hasExplicitCollectionMembers(opts) {
|
|
28201
|
+
const members = opts.members;
|
|
28202
|
+
return Array.isArray(members) && members.length > 0;
|
|
28203
|
+
}
|
|
28204
|
+
function collectionTypeFromWref(wref) {
|
|
28205
|
+
const local = wref.replace(/^wh:[^/]+\/[^/]+\//, "").replace(/@(?:HEAD|ALL|v\d+)$/, "");
|
|
28206
|
+
const shape = local.split("/")[0]?.toLowerCase();
|
|
28207
|
+
return shape === "pair" || shape === "set" || shape === "list" ? shape : undefined;
|
|
28208
|
+
}
|
|
28209
|
+
function assertSelectorBackedCollectionType(type, opts) {
|
|
28210
|
+
if (hasCollectionQuerySource(opts.query) && !hasCollectionSelectorAnchor(opts.query)) {
|
|
28211
|
+
throw new WarmHubError("VALIDATION_ERROR", "Selector-backed collection sources require shape, about, match, componentRef, or where; kind and excludeComponents only narrow an existing selector.");
|
|
28212
|
+
}
|
|
28213
|
+
if (opts.sourceRepo && !hasCollectionSelectorAnchor(opts.query)) {
|
|
28214
|
+
throw new WarmHubError("VALIDATION_ERROR", "sourceRepo requires a selector-backed collection query");
|
|
28215
|
+
}
|
|
28216
|
+
if (opts.sourceRepo && hasExplicitCollectionMembers(opts)) {
|
|
28217
|
+
throw new WarmHubError("VALIDATION_ERROR", "sourceRepo cannot be combined with explicit members; use canonical wh:org/repo/... member wrefs or omit sourceRepo.");
|
|
28218
|
+
}
|
|
28219
|
+
if (hasCollectionQuerySource(opts.query) && type !== "set") {
|
|
28220
|
+
throw new WarmHubError("VALIDATION_ERROR", "Selector-backed collection sources are only supported for set collections");
|
|
28221
|
+
}
|
|
28222
|
+
}
|
|
28101
28223
|
function trpcClientCodeToWarmHubCode(code) {
|
|
28102
28224
|
switch (code) {
|
|
28103
28225
|
case "BAD_REQUEST":
|
|
@@ -29319,6 +29441,144 @@ class WarmHubClient {
|
|
|
29319
29441
|
}
|
|
29320
29442
|
}
|
|
29321
29443
|
};
|
|
29444
|
+
collection = {
|
|
29445
|
+
create: async (orgName, repoName, opts) => {
|
|
29446
|
+
try {
|
|
29447
|
+
assertSelectorBackedCollectionType(opts.type, opts);
|
|
29448
|
+
return await this.trpc.collection.create.mutate({
|
|
29449
|
+
orgName,
|
|
29450
|
+
repoName,
|
|
29451
|
+
type: opts.type,
|
|
29452
|
+
name: opts.name,
|
|
29453
|
+
members: opts.members,
|
|
29454
|
+
from: opts.from,
|
|
29455
|
+
add: opts.add,
|
|
29456
|
+
remove: opts.remove,
|
|
29457
|
+
replaceMembers: opts.replaceMembers,
|
|
29458
|
+
query: opts.query,
|
|
29459
|
+
sourceOrgName: opts.sourceRepo?.orgName,
|
|
29460
|
+
sourceRepoName: opts.sourceRepo?.repoName,
|
|
29461
|
+
skipExisting: opts.skipExisting,
|
|
29462
|
+
message: opts.message,
|
|
29463
|
+
committer: opts.committer
|
|
29464
|
+
});
|
|
29465
|
+
} catch (error) {
|
|
29466
|
+
throw toWarmHubError(error);
|
|
29467
|
+
}
|
|
29468
|
+
},
|
|
29469
|
+
members: async (orgName, repoName, wref, opts) => {
|
|
29470
|
+
try {
|
|
29471
|
+
return await this.trpc.collection.members.query({
|
|
29472
|
+
orgName,
|
|
29473
|
+
repoName,
|
|
29474
|
+
wref,
|
|
29475
|
+
version: opts?.version,
|
|
29476
|
+
limit: opts?.limit,
|
|
29477
|
+
cursor: opts?.cursor
|
|
29478
|
+
});
|
|
29479
|
+
} catch (error) {
|
|
29480
|
+
throw toWarmHubError(error);
|
|
29481
|
+
}
|
|
29482
|
+
},
|
|
29483
|
+
membersIter: (orgName, repoName, wref, opts) => {
|
|
29484
|
+
let snapshotVersion = opts?.version;
|
|
29485
|
+
return paginate(async (cursor) => {
|
|
29486
|
+
const page = await this.collection.members(orgName, repoName, wref, {
|
|
29487
|
+
...opts,
|
|
29488
|
+
version: snapshotVersion,
|
|
29489
|
+
cursor
|
|
29490
|
+
});
|
|
29491
|
+
snapshotVersion ??= page.version;
|
|
29492
|
+
return page;
|
|
29493
|
+
}, (page) => page.items, opts?.cursor);
|
|
29494
|
+
},
|
|
29495
|
+
membersAll: async (orgName, repoName, wref, opts) => {
|
|
29496
|
+
const { max, ...pageOpts } = opts ?? {};
|
|
29497
|
+
let snapshotVersion = pageOpts.version;
|
|
29498
|
+
return await collectPaginatedPages(async (cursor) => {
|
|
29499
|
+
const page = await this.collection.members(orgName, repoName, wref, {
|
|
29500
|
+
...pageOpts,
|
|
29501
|
+
version: snapshotVersion,
|
|
29502
|
+
cursor
|
|
29503
|
+
});
|
|
29504
|
+
snapshotVersion ??= page.version;
|
|
29505
|
+
return page;
|
|
29506
|
+
}, (page) => page.items, max, pageOpts.cursor);
|
|
29507
|
+
},
|
|
29508
|
+
contains: async (orgName, repoName, wref, members, opts) => {
|
|
29509
|
+
try {
|
|
29510
|
+
return await this.trpc.collection.contains.query({
|
|
29511
|
+
orgName,
|
|
29512
|
+
repoName,
|
|
29513
|
+
wref,
|
|
29514
|
+
version: opts?.version,
|
|
29515
|
+
members,
|
|
29516
|
+
position: opts?.position
|
|
29517
|
+
});
|
|
29518
|
+
} catch (error) {
|
|
29519
|
+
throw toWarmHubError(error);
|
|
29520
|
+
}
|
|
29521
|
+
},
|
|
29522
|
+
diff: async (orgName, repoName, leftWref, rightWref, opts) => {
|
|
29523
|
+
try {
|
|
29524
|
+
return await this.trpc.collection.diff.query({
|
|
29525
|
+
orgName,
|
|
29526
|
+
repoName,
|
|
29527
|
+
leftWref,
|
|
29528
|
+
rightWref,
|
|
29529
|
+
leftVersion: opts?.leftVersion,
|
|
29530
|
+
rightVersion: opts?.rightVersion,
|
|
29531
|
+
mode: opts?.mode
|
|
29532
|
+
});
|
|
29533
|
+
} catch (error) {
|
|
29534
|
+
throw toWarmHubError(error);
|
|
29535
|
+
}
|
|
29536
|
+
},
|
|
29537
|
+
revise: async (orgName, repoName, wref, opts) => {
|
|
29538
|
+
try {
|
|
29539
|
+
const targetType = collectionTypeFromWref(wref);
|
|
29540
|
+
if (hasCollectionQuerySource(opts.query) && !hasCollectionSelectorAnchor(opts.query)) {
|
|
29541
|
+
throw new WarmHubError("VALIDATION_ERROR", "Selector-backed collection sources require shape, about, match, componentRef, or where; kind and excludeComponents only narrow an existing selector.");
|
|
29542
|
+
}
|
|
29543
|
+
if (opts.sourceRepo && !hasCollectionSelectorAnchor(opts.query)) {
|
|
29544
|
+
throw new WarmHubError("VALIDATION_ERROR", "sourceRepo requires a selector-backed collection query");
|
|
29545
|
+
}
|
|
29546
|
+
if (opts.sourceRepo && hasExplicitCollectionMembers(opts)) {
|
|
29547
|
+
throw new WarmHubError("VALIDATION_ERROR", "sourceRepo cannot be combined with explicit members; use canonical wh:org/repo/... member wrefs or omit sourceRepo.");
|
|
29548
|
+
}
|
|
29549
|
+
if (hasCollectionQuerySource(opts.query) && targetType && targetType !== "set") {
|
|
29550
|
+
throw new WarmHubError("VALIDATION_ERROR", "Selector-backed revise requires a Set/<name> target wref");
|
|
29551
|
+
}
|
|
29552
|
+
return await this.trpc.collection.revise.mutate({
|
|
29553
|
+
orgName,
|
|
29554
|
+
repoName,
|
|
29555
|
+
wref,
|
|
29556
|
+
members: opts.members,
|
|
29557
|
+
add: opts.add,
|
|
29558
|
+
remove: opts.remove,
|
|
29559
|
+
query: opts.query,
|
|
29560
|
+
sourceOrgName: opts.sourceRepo?.orgName,
|
|
29561
|
+
sourceRepoName: opts.sourceRepo?.repoName,
|
|
29562
|
+
message: opts.message,
|
|
29563
|
+
committer: opts.committer
|
|
29564
|
+
});
|
|
29565
|
+
} catch (error) {
|
|
29566
|
+
throw toWarmHubError(error);
|
|
29567
|
+
}
|
|
29568
|
+
},
|
|
29569
|
+
stats: async (orgName, repoName, wref, opts) => {
|
|
29570
|
+
try {
|
|
29571
|
+
return await this.trpc.collection.stats.query({
|
|
29572
|
+
orgName,
|
|
29573
|
+
repoName,
|
|
29574
|
+
wref,
|
|
29575
|
+
version: opts?.version
|
|
29576
|
+
});
|
|
29577
|
+
} catch (error) {
|
|
29578
|
+
throw toWarmHubError(error);
|
|
29579
|
+
}
|
|
29580
|
+
}
|
|
29581
|
+
};
|
|
29322
29582
|
thing = {
|
|
29323
29583
|
head: async (orgName, repoName, opts) => {
|
|
29324
29584
|
try {
|
|
@@ -29356,7 +29616,8 @@ class WarmHubClient {
|
|
|
29356
29616
|
repoName,
|
|
29357
29617
|
wref,
|
|
29358
29618
|
version,
|
|
29359
|
-
includeRetracted: opts?.includeRetracted
|
|
29619
|
+
includeRetracted: opts?.includeRetracted,
|
|
29620
|
+
dataMode: opts?.dataMode
|
|
29360
29621
|
});
|
|
29361
29622
|
} catch (error) {
|
|
29362
29623
|
throw toWarmHubError(error);
|
|
@@ -29417,7 +29678,8 @@ class WarmHubClient {
|
|
|
29417
29678
|
repoName,
|
|
29418
29679
|
wrefs: chunkWrefs,
|
|
29419
29680
|
version,
|
|
29420
|
-
includeRetracted: opts?.includeRetracted
|
|
29681
|
+
includeRetracted: opts?.includeRetracted,
|
|
29682
|
+
dataMode: opts?.dataMode
|
|
29421
29683
|
});
|
|
29422
29684
|
};
|
|
29423
29685
|
if (wrefs.length <= chunkSize) {
|
|
@@ -32882,7 +33144,7 @@ function emitPartialPageHint(ctx, count, _nextCursor, _limit) {
|
|
|
32882
33144
|
}
|
|
32883
33145
|
|
|
32884
33146
|
// ../../packages/warmhub-cli/src/domains/assertion/shared.ts
|
|
32885
|
-
var COLLECTION_TAGS = ["pair", "
|
|
33147
|
+
var COLLECTION_TAGS = ["pair", "set", "list"];
|
|
32886
33148
|
function parseAbout(raw) {
|
|
32887
33149
|
const colonIdx = raw.indexOf(":");
|
|
32888
33150
|
if (colonIdx === -1) {
|
|
@@ -32892,32 +33154,7 @@ function parseAbout(raw) {
|
|
|
32892
33154
|
if (!COLLECTION_TAGS.includes(tag)) {
|
|
32893
33155
|
return raw;
|
|
32894
33156
|
}
|
|
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
|
-
}
|
|
33157
|
+
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
33158
|
}
|
|
32922
33159
|
function renderAbout(out, c, result) {
|
|
32923
33160
|
const target = result.target;
|
|
@@ -33015,7 +33252,7 @@ var createFlags = {
|
|
|
33015
33252
|
name: flag.string({ description: "Assertion name" }),
|
|
33016
33253
|
shape: flag.string({ description: "Shape for assertion (required)" }),
|
|
33017
33254
|
data: flag.string({ description: "Data payload (JSON)" }),
|
|
33018
|
-
about: flag.string({ description: "Target wref
|
|
33255
|
+
about: flag.string({ description: "Target wref" }),
|
|
33019
33256
|
message: flag.string({ short: "m", description: "Commit message" }),
|
|
33020
33257
|
committer: flag.string({
|
|
33021
33258
|
description: "Committer thing wref (e.g. Agent/bot-1)"
|
|
@@ -33374,6 +33611,9 @@ function renderThing(out, c, result) {
|
|
|
33374
33611
|
out(` ${c.dim}revisedOn:${c.reset} ${formatTime(meta.revisedOn, now)}`);
|
|
33375
33612
|
}
|
|
33376
33613
|
}
|
|
33614
|
+
if (result.collection) {
|
|
33615
|
+
renderCollectionSummary(out, c, result.collection);
|
|
33616
|
+
}
|
|
33377
33617
|
const fields = shapeName && result.data ? collectionFields(shapeName, result.data) : null;
|
|
33378
33618
|
if (fields) {
|
|
33379
33619
|
for (const field of fields) {
|
|
@@ -33396,6 +33636,21 @@ function renderThing(out, c, result) {
|
|
|
33396
33636
|
}
|
|
33397
33637
|
}
|
|
33398
33638
|
}
|
|
33639
|
+
function renderCollectionSummary(out, c, collection) {
|
|
33640
|
+
out(` ${c.dim}collection:${c.reset} ${collection.type}`);
|
|
33641
|
+
out(` ${c.dim}members:${c.reset} ${collection.memberCount}`);
|
|
33642
|
+
if (collection.fullData)
|
|
33643
|
+
return;
|
|
33644
|
+
const limit = collection.inlineLimit ? ` > ${collection.inlineLimit}` : " above inline limit";
|
|
33645
|
+
out(` ${c.dim}data:${c.reset} elided (${collection.memberCount}${limit}; use --data-mode full)`);
|
|
33646
|
+
const preview = collection.preview ?? [];
|
|
33647
|
+
if (preview.length === 0)
|
|
33648
|
+
return;
|
|
33649
|
+
out(` ${c.dim}preview:${c.reset}`);
|
|
33650
|
+
for (const wref of preview) {
|
|
33651
|
+
out(` ${pinnedWref(c, wref)}`);
|
|
33652
|
+
}
|
|
33653
|
+
}
|
|
33399
33654
|
function renderDataBlock(out, data, indent) {
|
|
33400
33655
|
const lines = JSON.stringify(data, null, 2).split(`
|
|
33401
33656
|
`);
|
|
@@ -33587,7 +33842,7 @@ var historyFlags = {
|
|
|
33587
33842
|
description: "Allow retracted shape/about targets to resolve"
|
|
33588
33843
|
}),
|
|
33589
33844
|
"resolve-collections": flag.boolean({
|
|
33590
|
-
description: "Include assertions about collections (Pair/
|
|
33845
|
+
description: "Include assertions about collections (Pair/Set/List) containing the target. Only applies with --about."
|
|
33591
33846
|
})
|
|
33592
33847
|
};
|
|
33593
33848
|
var handleHistory = async (ctx, { flags, args }) => {
|
|
@@ -33978,7 +34233,7 @@ var queryFlags = {
|
|
|
33978
34233
|
description: "Include retracted things"
|
|
33979
34234
|
}),
|
|
33980
34235
|
"resolve-collections": flag.boolean({
|
|
33981
|
-
description: "Include assertions about collections (Pair/
|
|
34236
|
+
description: "Include assertions about collections (Pair/Set/List) containing the target. Only applies with --about."
|
|
33982
34237
|
}),
|
|
33983
34238
|
component: flag.string({
|
|
33984
34239
|
description: "Filter to things owned by this component (Org/Name ref)"
|
|
@@ -34391,7 +34646,7 @@ var searchFlags = {
|
|
|
34391
34646
|
description: "Include retracted things"
|
|
34392
34647
|
}),
|
|
34393
34648
|
"resolve-collections": flag.boolean({
|
|
34394
|
-
description: "Include assertions about collections (Pair/
|
|
34649
|
+
description: "Include assertions about collections (Pair/Set/List) containing the target. Only applies with --about."
|
|
34395
34650
|
}),
|
|
34396
34651
|
limit: flag.number({ description: "Max results (default: 25, max: 500)" }),
|
|
34397
34652
|
cursor: flag.string({ description: "Opaque pagination cursor (text mode)" }),
|
|
@@ -34554,6 +34809,9 @@ var viewFlags = {
|
|
|
34554
34809
|
}),
|
|
34555
34810
|
file: flag.string({
|
|
34556
34811
|
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."
|
|
34812
|
+
}),
|
|
34813
|
+
"data-mode": flag.string({
|
|
34814
|
+
description: "Collection data mode: auto (default) or full. Use full to force large collection bodies into thing view output."
|
|
34557
34815
|
})
|
|
34558
34816
|
};
|
|
34559
34817
|
var MAX_GET_MANY_WREFS = 500;
|
|
@@ -34568,6 +34826,13 @@ async function readStreamUtf8(input) {
|
|
|
34568
34826
|
function parseLineList(text) {
|
|
34569
34827
|
return text.split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#"));
|
|
34570
34828
|
}
|
|
34829
|
+
function validateDataMode(value) {
|
|
34830
|
+
if (value === undefined)
|
|
34831
|
+
return;
|
|
34832
|
+
if (value === "auto" || value === "full")
|
|
34833
|
+
return value;
|
|
34834
|
+
usageError("--data-mode must be auto or full", "wh thing view Set/wake-voters --data-mode full");
|
|
34835
|
+
}
|
|
34571
34836
|
async function collectWrefs(opts) {
|
|
34572
34837
|
const dashPositional = opts.positionals.includes("-");
|
|
34573
34838
|
const cleanPositionals = opts.positionals.filter((a) => a !== "-");
|
|
@@ -34606,12 +34871,16 @@ async function runSingleView(ctx, wref, flags) {
|
|
|
34606
34871
|
const depth = flags.depth;
|
|
34607
34872
|
const { org, repo } = looksLikeDurableId(wref) && depth === undefined ? parseOrgRepoOptional(getRepoRef(ctx), ctx.config) : parseOrgRepo(getRepoRef(ctx), ctx.config);
|
|
34608
34873
|
const includeRetracted = flags["include-retracted"] || version !== undefined;
|
|
34874
|
+
const dataMode = validateDataMode(flags["data-mode"]);
|
|
34609
34875
|
if (depth !== undefined && (depth < 1 || depth > 5)) {
|
|
34610
34876
|
usageError("Usage: wh thing view <wref> --depth <1-5>", "wh thing view Game/base --depth 2");
|
|
34611
34877
|
}
|
|
34612
34878
|
if (depth !== undefined && ctx.liveMode) {
|
|
34613
34879
|
usageError("--depth is not supported with --live", "wh thing view Game/base --depth 2");
|
|
34614
34880
|
}
|
|
34881
|
+
if (depth !== undefined && dataMode !== undefined) {
|
|
34882
|
+
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");
|
|
34883
|
+
}
|
|
34615
34884
|
if (depth !== undefined && (flags["include-retracted"] || version !== undefined)) {
|
|
34616
34885
|
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
34886
|
}
|
|
@@ -34619,7 +34888,8 @@ async function runSingleView(ctx, wref, flags) {
|
|
|
34619
34888
|
await runLive({
|
|
34620
34889
|
apiUrl: ctx.config.apiUrl,
|
|
34621
34890
|
poll: (c) => c.thing.get(org, repo, wref, version, {
|
|
34622
|
-
includeRetracted
|
|
34891
|
+
includeRetracted,
|
|
34892
|
+
dataMode
|
|
34623
34893
|
}),
|
|
34624
34894
|
render: (r) => renderThing(ctx.out, ctx.colors, r),
|
|
34625
34895
|
out: ctx.out,
|
|
@@ -34644,7 +34914,8 @@ async function runSingleView(ctx, wref, flags) {
|
|
|
34644
34914
|
return;
|
|
34645
34915
|
}
|
|
34646
34916
|
const result = await ctx.client.thing.get(org, repo, wref, version, {
|
|
34647
|
-
includeRetracted
|
|
34917
|
+
includeRetracted,
|
|
34918
|
+
dataMode
|
|
34648
34919
|
});
|
|
34649
34920
|
writeOutput(ctx, result, () => renderThing(ctx.out, ctx.colors, result));
|
|
34650
34921
|
}
|
|
@@ -34652,7 +34923,8 @@ async function runBatchView(ctx, wrefs, flags) {
|
|
|
34652
34923
|
const allDurable = wrefs.length > 0 && wrefs.every(looksLikeDurableId);
|
|
34653
34924
|
const { org, repo } = allDurable ? parseOrgRepoOptional(getRepoRef(ctx), ctx.config) : parseOrgRepo(getRepoRef(ctx), ctx.config);
|
|
34654
34925
|
const includeRetracted = flags["include-retracted"] || flags.version !== undefined;
|
|
34655
|
-
const
|
|
34926
|
+
const dataMode = validateDataMode(flags["data-mode"]);
|
|
34927
|
+
const result = await ctx.client.thing.getMany(org, repo, wrefs, flags.version, { includeRetracted, dataMode });
|
|
34656
34928
|
if (ctx.format === "jsonl") {
|
|
34657
34929
|
for (const event of walkBatchResult(wrefs, result, flags.version)) {
|
|
34658
34930
|
if (event.kind === "miss") {
|
|
@@ -34995,7 +35267,9 @@ var handleHistory2 = async (ctx, { flags, args }) => {
|
|
|
34995
35267
|
writePageOutput(ctx, result.versions, { limit, nextCursor: result.nextCursor ?? null }, () => renderHistory(ctx.out, ctx.colors, result));
|
|
34996
35268
|
};
|
|
34997
35269
|
var listFlags = {
|
|
34998
|
-
about: flag.string({
|
|
35270
|
+
about: flag.string({
|
|
35271
|
+
description: "Target wref (thing or shape, required)"
|
|
35272
|
+
}),
|
|
34999
35273
|
shape: flag.string({ description: "Filter by shape" }),
|
|
35000
35274
|
depth: flag.number({ description: "Assertion depth" }),
|
|
35001
35275
|
limit: flag.number({
|
|
@@ -35006,7 +35280,7 @@ var listFlags = {
|
|
|
35006
35280
|
count: flag.boolean({ description: "Return count of matching assertions" }),
|
|
35007
35281
|
match: flag.string({ description: "Filter by wref glob pattern" }),
|
|
35008
35282
|
"resolve-collections": flag.boolean({
|
|
35009
|
-
description: "Include assertions about collections (Pair/
|
|
35283
|
+
description: "Include assertions about collections (Pair/Set/List) containing the target."
|
|
35010
35284
|
}),
|
|
35011
35285
|
"include-retracted": flag.boolean({
|
|
35012
35286
|
description: "Include retracted assertions"
|
|
@@ -35189,7 +35463,7 @@ var ASSERTION_DOMAIN = defineDomain({
|
|
|
35189
35463
|
flags: createFlags,
|
|
35190
35464
|
examples: [
|
|
35191
35465
|
`wh assertion create --shape belief --about player --data '{"confidence":0.8}'`,
|
|
35192
|
-
`wh assertion create --shape Distance --about
|
|
35466
|
+
`wh assertion create --shape Distance --about Pair/location-distance --data '{"value":5}'`
|
|
35193
35467
|
],
|
|
35194
35468
|
handler: handleCreate
|
|
35195
35469
|
},
|
|
@@ -36580,6 +36854,693 @@ var CHANNEL_DOMAIN = defineDomain({
|
|
|
36580
36854
|
handler: handleChannel
|
|
36581
36855
|
});
|
|
36582
36856
|
|
|
36857
|
+
// ../../packages/warmhub-cli/src/domains/collection-helpers.ts
|
|
36858
|
+
import { readFileSync as readFileSync6 } from "node:fs";
|
|
36859
|
+
function parseMemberList(values) {
|
|
36860
|
+
return (values ?? []).flatMap((value) => value.split(",")).map((value) => value.trim()).filter(Boolean);
|
|
36861
|
+
}
|
|
36862
|
+
async function readMembersFromSources(ctx, opts) {
|
|
36863
|
+
const field = opts.wrefField ?? "wref";
|
|
36864
|
+
const members = [
|
|
36865
|
+
...opts.positionals ?? [],
|
|
36866
|
+
...parseMemberList(opts.members)
|
|
36867
|
+
];
|
|
36868
|
+
const fileIsStdin = opts.file === "-";
|
|
36869
|
+
if ((opts.stdin || fileIsStdin) && isTTY(ctx.stdin ?? process.stdin)) {
|
|
36870
|
+
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");
|
|
36871
|
+
}
|
|
36872
|
+
if (opts.file && !fileIsStdin) {
|
|
36873
|
+
let raw;
|
|
36874
|
+
try {
|
|
36875
|
+
raw = readFileSync6(opts.file, "utf8");
|
|
36876
|
+
} catch (error) {
|
|
36877
|
+
const code = error.code;
|
|
36878
|
+
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.");
|
|
36879
|
+
}
|
|
36880
|
+
members.push(...parseMembersPayload(raw, opts.label ?? "--file", field));
|
|
36881
|
+
}
|
|
36882
|
+
if (opts.stdin || fileIsStdin) {
|
|
36883
|
+
const raw = await readStreamUtf82(ctx.stdin ?? process.stdin);
|
|
36884
|
+
members.push(...parseMembersPayload(raw, opts.label ?? "stdin", field));
|
|
36885
|
+
}
|
|
36886
|
+
return members;
|
|
36887
|
+
}
|
|
36888
|
+
function hasCollectionQuerySource2(source) {
|
|
36889
|
+
return !!source.shape || !!source.kind || !!source.about || !!source.match || !!source.componentRef || source.excludeComponents === true || (source.where?.length ?? 0) > 0;
|
|
36890
|
+
}
|
|
36891
|
+
function hasCollectionSelectorAnchor2(source) {
|
|
36892
|
+
return !!source.shape || !!source.about || !!source.match || !!source.componentRef || (source.where?.length ?? 0) > 0;
|
|
36893
|
+
}
|
|
36894
|
+
function requireMembers(members, example) {
|
|
36895
|
+
if (members.length === 0) {
|
|
36896
|
+
usageError("At least one collection member is required", example);
|
|
36897
|
+
}
|
|
36898
|
+
}
|
|
36899
|
+
function renderMutation(ctx, result) {
|
|
36900
|
+
const c = ctx.colors;
|
|
36901
|
+
const action = result.status === "noop" ? "=" : "+";
|
|
36902
|
+
const color = result.status === "noop" ? c.dim : c.green;
|
|
36903
|
+
ctx.out(`${color}${action}${c.reset} ${displayName(c, result.wref)} ${c.dim}${result.type} ${result.memberCount} members${c.reset}`);
|
|
36904
|
+
}
|
|
36905
|
+
function renderMembers(ctx, result) {
|
|
36906
|
+
const c = ctx.colors;
|
|
36907
|
+
if (result.items.length === 0) {
|
|
36908
|
+
ctx.out(`${c.dim}No members${c.reset}`);
|
|
36909
|
+
return;
|
|
36910
|
+
}
|
|
36911
|
+
for (const item of result.items) {
|
|
36912
|
+
const position = item.position ?? 0;
|
|
36913
|
+
ctx.out(`${String(position).padStart(4, " ")} ${pinnedWref(c, item.wref)}`);
|
|
36914
|
+
}
|
|
36915
|
+
}
|
|
36916
|
+
function renderContains(ctx, result) {
|
|
36917
|
+
const c = ctx.colors;
|
|
36918
|
+
for (const item of result.results) {
|
|
36919
|
+
const marker = item.contains ? ctx.chars.check : ctx.chars.cross;
|
|
36920
|
+
const color = item.contains ? c.green : c.red;
|
|
36921
|
+
const at = item.positions === undefined || item.positions.length === 0 ? "" : ` ${c.dim}@${item.positions.join(",")}${c.reset}`;
|
|
36922
|
+
ctx.out(`${color}${marker}${c.reset} ${pinnedWref(c, item.member)}${at}`);
|
|
36923
|
+
}
|
|
36924
|
+
}
|
|
36925
|
+
function renderDiff(ctx, result) {
|
|
36926
|
+
const c = ctx.colors;
|
|
36927
|
+
if (result.mode === "ordered") {
|
|
36928
|
+
if (result.changed.length === 0) {
|
|
36929
|
+
ctx.out(`${c.dim}No ordered differences${c.reset}`);
|
|
36930
|
+
return;
|
|
36931
|
+
}
|
|
36932
|
+
for (const item of result.changed) {
|
|
36933
|
+
const left = item.left?.wref ?? `${c.dim}(none)${c.reset}`;
|
|
36934
|
+
const right = item.right?.wref ?? `${c.dim}(none)${c.reset}`;
|
|
36935
|
+
ctx.out(`${String(item.position).padStart(4, " ")} ${left} -> ${right}`);
|
|
36936
|
+
}
|
|
36937
|
+
return;
|
|
36938
|
+
}
|
|
36939
|
+
if (result.added.length === 0 && result.removed.length === 0) {
|
|
36940
|
+
ctx.out(`${c.dim}No membership differences${c.reset}`);
|
|
36941
|
+
return;
|
|
36942
|
+
}
|
|
36943
|
+
for (const member of result.added) {
|
|
36944
|
+
ctx.out(`${c.green}+${c.reset} ${member.wref}`);
|
|
36945
|
+
}
|
|
36946
|
+
for (const member of result.removed) {
|
|
36947
|
+
ctx.out(`${c.red}-${c.reset} ${member.wref}`);
|
|
36948
|
+
}
|
|
36949
|
+
}
|
|
36950
|
+
function renderStats(ctx, result) {
|
|
36951
|
+
const c = ctx.colors;
|
|
36952
|
+
ctx.out(`${pinnedWref(c, result.wref)} ${c.dim}${result.type}${c.reset}`);
|
|
36953
|
+
ctx.out(`members: ${result.memberCount}`);
|
|
36954
|
+
ctx.out(`unique: ${result.uniqueMemberCount}`);
|
|
36955
|
+
}
|
|
36956
|
+
function memberFromUnknown(value, field, label) {
|
|
36957
|
+
if (typeof value === "string" && value.trim().length > 0) {
|
|
36958
|
+
return value.trim();
|
|
36959
|
+
}
|
|
36960
|
+
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
36961
|
+
const raw = value[field];
|
|
36962
|
+
if (typeof raw === "string" && raw.trim().length > 0) {
|
|
36963
|
+
return raw.trim();
|
|
36964
|
+
}
|
|
36965
|
+
}
|
|
36966
|
+
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"}.`);
|
|
36967
|
+
}
|
|
36968
|
+
function parseMembersPayload(raw, label, field = "wref") {
|
|
36969
|
+
const trimmed = raw.trim();
|
|
36970
|
+
if (!trimmed)
|
|
36971
|
+
return [];
|
|
36972
|
+
if (trimmed.startsWith("[")) {
|
|
36973
|
+
const parsed = safeParseJson(trimmed, label);
|
|
36974
|
+
if (!Array.isArray(parsed)) {
|
|
36975
|
+
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}".`);
|
|
36976
|
+
}
|
|
36977
|
+
return parsed.map((entry) => memberFromUnknown(entry, field, label));
|
|
36978
|
+
}
|
|
36979
|
+
if (trimmed.startsWith("{")) {
|
|
36980
|
+
let objectParseError;
|
|
36981
|
+
try {
|
|
36982
|
+
const parsed = safeParseJson(trimmed, label);
|
|
36983
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed) && Array.isArray(parsed.members)) {
|
|
36984
|
+
return parsed.members.map((entry) => memberFromUnknown(entry, field, label));
|
|
36985
|
+
}
|
|
36986
|
+
return [memberFromUnknown(parsed, field, label)];
|
|
36987
|
+
} catch (error) {
|
|
36988
|
+
objectParseError = error;
|
|
36989
|
+
}
|
|
36990
|
+
const lines = trimmed.split(/\r?\n/).filter((line) => line.trim());
|
|
36991
|
+
if (lines.length > 1) {
|
|
36992
|
+
return lines.map((line) => memberFromUnknown(safeParseJson(line, label), field, label));
|
|
36993
|
+
}
|
|
36994
|
+
throw objectParseError;
|
|
36995
|
+
}
|
|
36996
|
+
return trimmed.split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#"));
|
|
36997
|
+
}
|
|
36998
|
+
async function readStreamUtf82(input) {
|
|
36999
|
+
let data = "";
|
|
37000
|
+
input.setEncoding?.("utf8");
|
|
37001
|
+
for await (const chunk of input) {
|
|
37002
|
+
data += typeof chunk === "string" ? chunk : chunk.toString("utf8");
|
|
37003
|
+
}
|
|
37004
|
+
return data;
|
|
37005
|
+
}
|
|
37006
|
+
|
|
37007
|
+
// ../../packages/warmhub-cli/src/domains/collection.ts
|
|
37008
|
+
var COLLECTION_TYPES = ["pair", "set", "list"];
|
|
37009
|
+
var commonWriteFlags = {
|
|
37010
|
+
message: flag.string({ short: "m", description: "Commit message" }),
|
|
37011
|
+
committer: flag.string({
|
|
37012
|
+
description: "Committer thing wref (e.g. Agent/bot-1)"
|
|
37013
|
+
})
|
|
37014
|
+
};
|
|
37015
|
+
var collectionInputFlags = {
|
|
37016
|
+
members: flag.string({
|
|
37017
|
+
multiple: true,
|
|
37018
|
+
description: "Collection member wrefs. May be repeated; comma-separated values are also accepted."
|
|
37019
|
+
}),
|
|
37020
|
+
file: flag.string({
|
|
37021
|
+
description: "Read member wrefs from a file. Supports newline text, JSON array, JSON object with members, or JSONL. Use --file=- for stdin."
|
|
37022
|
+
}),
|
|
37023
|
+
stdin: flag.boolean({
|
|
37024
|
+
description: "Read member wrefs from stdin. Supports newline text, JSON array, JSON object with members, or JSONL."
|
|
37025
|
+
}),
|
|
37026
|
+
"wref-field": flag.string({
|
|
37027
|
+
description: "Object field to read when --file/--stdin contains JSON objects (default: wref)."
|
|
37028
|
+
})
|
|
37029
|
+
};
|
|
37030
|
+
var collectionQueryFlags = {
|
|
37031
|
+
shape: flag.string({ description: "Select set members by shape" }),
|
|
37032
|
+
kind: flag.string({ description: "Select set members by kind" }),
|
|
37033
|
+
about: flag.string({ description: "Select set members by about wref" }),
|
|
37034
|
+
match: flag.string({
|
|
37035
|
+
description: "Select set members by the same name pattern accepted by wh thing query --match"
|
|
37036
|
+
}),
|
|
37037
|
+
component: flag.string({
|
|
37038
|
+
description: "Select set members owned by this component (Org/Name ref)"
|
|
37039
|
+
}),
|
|
37040
|
+
"exclude-components": flag.boolean({
|
|
37041
|
+
description: "Exclude component-owned records from selector-backed sets"
|
|
37042
|
+
}),
|
|
37043
|
+
where: flag.string({
|
|
37044
|
+
multiple: true,
|
|
37045
|
+
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.`
|
|
37046
|
+
}),
|
|
37047
|
+
"source-repo": flag.string({
|
|
37048
|
+
description: "Read selector-backed set members from this source repo (org/repo). The collection is written to the target repo."
|
|
37049
|
+
})
|
|
37050
|
+
};
|
|
37051
|
+
var collectionCreateFlags = {
|
|
37052
|
+
type: flag.string({
|
|
37053
|
+
description: "Collection type: pair, set, or list"
|
|
37054
|
+
}),
|
|
37055
|
+
name: flag.string({
|
|
37056
|
+
description: "Collection local name. Collections are ordinary named things."
|
|
37057
|
+
}),
|
|
37058
|
+
"skip-existing": flag.boolean({
|
|
37059
|
+
description: "No-op if a named collection already exists. Only valid with --name."
|
|
37060
|
+
}),
|
|
37061
|
+
from: flag.string({
|
|
37062
|
+
description: "Initialize from an existing collection wref"
|
|
37063
|
+
}),
|
|
37064
|
+
add: flag.string({
|
|
37065
|
+
multiple: true,
|
|
37066
|
+
description: "With --from, member wrefs to add. May be repeated; comma-separated values are also accepted."
|
|
37067
|
+
}),
|
|
37068
|
+
remove: flag.string({
|
|
37069
|
+
multiple: true,
|
|
37070
|
+
description: "With --from, member wrefs to remove. May be repeated; comma-separated values are also accepted."
|
|
37071
|
+
}),
|
|
37072
|
+
"replace-file": flag.string({
|
|
37073
|
+
description: "With --from, replace membership from a file. Supports newline text, JSON array, JSON object with members, or JSONL."
|
|
37074
|
+
}),
|
|
37075
|
+
"replace-stdin": flag.boolean({
|
|
37076
|
+
description: "With --from, replace membership from stdin. Supports newline text, JSON array, JSON object with members, or JSONL."
|
|
37077
|
+
}),
|
|
37078
|
+
...collectionInputFlags,
|
|
37079
|
+
...collectionQueryFlags,
|
|
37080
|
+
...commonWriteFlags
|
|
37081
|
+
};
|
|
37082
|
+
var collectionMembersFlags = {
|
|
37083
|
+
limit: flag.number({
|
|
37084
|
+
description: "Max members per page (default: 50, max: 500)"
|
|
37085
|
+
}),
|
|
37086
|
+
cursor: flag.string({ description: "Opaque pagination cursor" }),
|
|
37087
|
+
all: flag.boolean({ description: "Fetch all pages" }),
|
|
37088
|
+
version: flag.number({ description: "Specific version number" })
|
|
37089
|
+
};
|
|
37090
|
+
var collectionContainsFlags = {
|
|
37091
|
+
position: flag.number({
|
|
37092
|
+
description: "For list checks, require the member at this zero-based index"
|
|
37093
|
+
}),
|
|
37094
|
+
version: flag.number({
|
|
37095
|
+
description: "Specific collection version number. Member inputs are still pinned before comparison; use pinned @vN members for historical membership checks."
|
|
37096
|
+
}),
|
|
37097
|
+
...collectionInputFlags
|
|
37098
|
+
};
|
|
37099
|
+
var collectionDiffFlags = {
|
|
37100
|
+
mode: flag.string({
|
|
37101
|
+
description: "Diff mode: auto, membership, or ordered"
|
|
37102
|
+
}),
|
|
37103
|
+
"left-version": flag.number({
|
|
37104
|
+
description: "Specific left collection version"
|
|
37105
|
+
}),
|
|
37106
|
+
"right-version": flag.number({
|
|
37107
|
+
description: "Specific right collection version"
|
|
37108
|
+
})
|
|
37109
|
+
};
|
|
37110
|
+
var collectionReviseFlags = {
|
|
37111
|
+
add: flag.string({
|
|
37112
|
+
multiple: true,
|
|
37113
|
+
description: "For set collections, member wrefs to add. May be repeated; comma-separated values are also accepted."
|
|
37114
|
+
}),
|
|
37115
|
+
remove: flag.string({
|
|
37116
|
+
multiple: true,
|
|
37117
|
+
description: "For set collections, member wrefs to remove. May be repeated; comma-separated values are also accepted."
|
|
37118
|
+
}),
|
|
37119
|
+
...collectionInputFlags,
|
|
37120
|
+
...collectionQueryFlags,
|
|
37121
|
+
...commonWriteFlags
|
|
37122
|
+
};
|
|
37123
|
+
var collectionStatsFlags = {
|
|
37124
|
+
version: flag.number({ description: "Specific collection version number" })
|
|
37125
|
+
};
|
|
37126
|
+
function validateCollectionType(value) {
|
|
37127
|
+
if (!value || !COLLECTION_TYPES.includes(value)) {
|
|
37128
|
+
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"');
|
|
37129
|
+
}
|
|
37130
|
+
return value;
|
|
37131
|
+
}
|
|
37132
|
+
function validateDiffMode(value) {
|
|
37133
|
+
if (value === undefined)
|
|
37134
|
+
return;
|
|
37135
|
+
if (value === "auto" || value === "membership" || value === "ordered") {
|
|
37136
|
+
return value;
|
|
37137
|
+
}
|
|
37138
|
+
usageError("--mode must be one of: auto, membership, ordered", "wh collection diff Set/a Set/b --mode membership");
|
|
37139
|
+
}
|
|
37140
|
+
function collectionQuerySourceFromFlags(flags) {
|
|
37141
|
+
const where = (flags.where ?? []).map(parseWhereFlag);
|
|
37142
|
+
const kind = validateKind(flags.kind);
|
|
37143
|
+
return {
|
|
37144
|
+
...flags.shape ? { shape: flags.shape } : {},
|
|
37145
|
+
...kind ? { kind } : {},
|
|
37146
|
+
...flags.about ? { about: flags.about } : {},
|
|
37147
|
+
...flags.match ? { match: flags.match } : {},
|
|
37148
|
+
...flags.component ? { componentRef: flags.component } : {},
|
|
37149
|
+
...flags["exclude-components"] ? { excludeComponents: flags["exclude-components"] } : {},
|
|
37150
|
+
...where.length > 0 ? { where } : {}
|
|
37151
|
+
};
|
|
37152
|
+
}
|
|
37153
|
+
function parseSourceRepoFlag(value) {
|
|
37154
|
+
if (!value)
|
|
37155
|
+
return;
|
|
37156
|
+
const parsed = splitRepoSlug(value);
|
|
37157
|
+
if (!parsed) {
|
|
37158
|
+
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");
|
|
37159
|
+
}
|
|
37160
|
+
return { orgName: parsed.org, repoName: parsed.repo };
|
|
37161
|
+
}
|
|
37162
|
+
function requireQuerySourceForSourceRepo(sourceRepo, querySource, example) {
|
|
37163
|
+
if (!sourceRepo || hasCollectionSelectorAnchor2(querySource))
|
|
37164
|
+
return;
|
|
37165
|
+
usageError("--source-repo requires a selector source", example);
|
|
37166
|
+
}
|
|
37167
|
+
function requireSelectorAnchorForQuerySource(querySource, example) {
|
|
37168
|
+
if (!hasCollectionQuerySource2(querySource) || hasCollectionSelectorAnchor2(querySource)) {
|
|
37169
|
+
return;
|
|
37170
|
+
}
|
|
37171
|
+
usageError("Selector-backed collection sources require shape, about, match, componentRef, or where; kind and exclude-components only narrow an existing selector.", example);
|
|
37172
|
+
}
|
|
37173
|
+
function requireSetForQuerySource(type, source, example) {
|
|
37174
|
+
if (!hasCollectionQuerySource2(source) || type === "set")
|
|
37175
|
+
return;
|
|
37176
|
+
usageError("Selector-backed collection sources are only supported for set collections", example);
|
|
37177
|
+
}
|
|
37178
|
+
function normalizeCreateMembers(type, members) {
|
|
37179
|
+
return type === "set" ? Array.from(new Set(members)) : members;
|
|
37180
|
+
}
|
|
37181
|
+
function hasDeferredMemberSource(flags) {
|
|
37182
|
+
return !!flags.file || !!flags.stdin;
|
|
37183
|
+
}
|
|
37184
|
+
function isMissingCollectionMemberError(error) {
|
|
37185
|
+
const candidate = error;
|
|
37186
|
+
const code = candidate.code ?? candidate.kind;
|
|
37187
|
+
return code === "VALIDATION_ERROR" && /requires (?:at least|exactly) \d+ member/.test(candidate.message ?? "");
|
|
37188
|
+
}
|
|
37189
|
+
function collectionTypeFromWref2(wref) {
|
|
37190
|
+
const local = wref.replace(/^wh:[^/]+\/[^/]+\//, "").replace(/@(?:HEAD|ALL|v\d+)$/, "");
|
|
37191
|
+
const shape = local.split("/")[0]?.toLowerCase();
|
|
37192
|
+
return COLLECTION_TYPES.includes(shape) ? shape : undefined;
|
|
37193
|
+
}
|
|
37194
|
+
function parseCollectionReadRepo(ctx, wrefs) {
|
|
37195
|
+
const allDurable = wrefs.length > 0 && wrefs.every(looksLikeDurableId);
|
|
37196
|
+
return allDurable ? parseOrgRepoOptional(getRepoRef(ctx), ctx.config) : parseOrgRepo(getRepoRef(ctx), ctx.config);
|
|
37197
|
+
}
|
|
37198
|
+
var handleCollectionCreate = async (ctx, { flags, args }) => {
|
|
37199
|
+
if (args.length > 0) {
|
|
37200
|
+
usageError(`Unexpected argument: '${args[0]}'`, "Use --members for explicit collection members: wh collection create --type set --name audited --members Location/a,Location/b");
|
|
37201
|
+
}
|
|
37202
|
+
const { org, repo } = parseOrgRepo(getRepoRef(ctx), ctx.config);
|
|
37203
|
+
const type = validateCollectionType(flags.type);
|
|
37204
|
+
const querySource = collectionQuerySourceFromFlags(flags);
|
|
37205
|
+
const sourceRepo = parseSourceRepoFlag(flags["source-repo"]);
|
|
37206
|
+
const add = parseMemberList(flags.add);
|
|
37207
|
+
const remove = parseMemberList(flags.remove);
|
|
37208
|
+
requireQuerySourceForSourceRepo(sourceRepo, querySource, "wh collection create --type set --name wake-voters --source-repo data/nc-voters --shape Voter --where county=Wake");
|
|
37209
|
+
requireSelectorAnchorForQuerySource(querySource, 'wh collection create --type set --name voters --match "Voter/*" -m "snapshot"');
|
|
37210
|
+
requireSetForQuerySource(type, querySource, 'wh collection create --type set --name voters --match "Voter/*" -m "snapshot"');
|
|
37211
|
+
if (flags.from && hasCollectionQuerySource2(querySource)) {
|
|
37212
|
+
usageError("--from cannot be combined with selector flags", 'wh collection create --type set --name today --from Set/yesterday --add Location/c -m "delta"');
|
|
37213
|
+
}
|
|
37214
|
+
if (flags.from && sourceRepo) {
|
|
37215
|
+
usageError("--from cannot be combined with --source-repo", 'wh collection create --type set --name today --from Set/yesterday --add Location/c -m "delta"');
|
|
37216
|
+
}
|
|
37217
|
+
if (flags.from && (flags.members || flags.file || flags.stdin)) {
|
|
37218
|
+
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"');
|
|
37219
|
+
}
|
|
37220
|
+
if ((flags["replace-file"] || flags["replace-stdin"]) && (add.length > 0 || remove.length > 0)) {
|
|
37221
|
+
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"');
|
|
37222
|
+
}
|
|
37223
|
+
if (!flags.from && (add.length > 0 || remove.length > 0 || flags["replace-file"] || flags["replace-stdin"])) {
|
|
37224
|
+
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"');
|
|
37225
|
+
}
|
|
37226
|
+
if (!flags.name) {
|
|
37227
|
+
usageError("Collection create requires --name", 'wh collection create --type set --name audited --members Location/a,Location/b -m "audit snapshot"');
|
|
37228
|
+
}
|
|
37229
|
+
if (flags["skip-existing"] && !flags.name) {
|
|
37230
|
+
usageError("--skip-existing requires --name", "wh collection create --type set --name voters --members Voter/a --skip-existing");
|
|
37231
|
+
}
|
|
37232
|
+
const queryBacked = hasCollectionQuerySource2(querySource);
|
|
37233
|
+
const replaceMembers = flags.from && (flags["replace-file"] || flags["replace-stdin"]) ? await readMembersFromSources(ctx, {
|
|
37234
|
+
file: flags["replace-file"],
|
|
37235
|
+
stdin: flags["replace-stdin"],
|
|
37236
|
+
wrefField: flags["wref-field"],
|
|
37237
|
+
label: "replacement members"
|
|
37238
|
+
}) : undefined;
|
|
37239
|
+
const inlineMembers = normalizeCreateMembers(type, parseMemberList(flags.members));
|
|
37240
|
+
if (flags["skip-existing"] && flags.name && !queryBacked && inlineMembers.length === 0 && hasDeferredMemberSource(flags)) {
|
|
37241
|
+
try {
|
|
37242
|
+
const result2 = await ctx.client.collection.create(org, repo, {
|
|
37243
|
+
type,
|
|
37244
|
+
name: flags.name,
|
|
37245
|
+
members: [],
|
|
37246
|
+
skipExisting: true,
|
|
37247
|
+
message: flags.message,
|
|
37248
|
+
committer: flags.committer
|
|
37249
|
+
});
|
|
37250
|
+
writeOutput(ctx, result2, () => renderMutation(ctx, result2));
|
|
37251
|
+
return;
|
|
37252
|
+
} catch (error) {
|
|
37253
|
+
if (!isMissingCollectionMemberError(error)) {
|
|
37254
|
+
throw error;
|
|
37255
|
+
}
|
|
37256
|
+
}
|
|
37257
|
+
}
|
|
37258
|
+
const explicitMembers = await readMembersFromSources(ctx, {
|
|
37259
|
+
members: flags.members,
|
|
37260
|
+
file: flags.from ? undefined : flags.file,
|
|
37261
|
+
stdin: flags.from ? undefined : flags.stdin,
|
|
37262
|
+
wrefField: flags["wref-field"],
|
|
37263
|
+
label: "collection members"
|
|
37264
|
+
});
|
|
37265
|
+
const members = normalizeCreateMembers(type, explicitMembers);
|
|
37266
|
+
if (sourceRepo && members.length > 0) {
|
|
37267
|
+
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");
|
|
37268
|
+
}
|
|
37269
|
+
if (!queryBacked && !flags.from) {
|
|
37270
|
+
requireMembers(members, 'wh collection create --type set --name audited --members Location/a,Location/b -m "audit snapshot"');
|
|
37271
|
+
}
|
|
37272
|
+
const result = queryBacked ? sourceRepo ? await ctx.client.collection.create(org, repo, {
|
|
37273
|
+
type,
|
|
37274
|
+
name: flags.name,
|
|
37275
|
+
...flags.from ? { from: flags.from } : {},
|
|
37276
|
+
...add.length > 0 ? { add } : {},
|
|
37277
|
+
...remove.length > 0 ? { remove } : {},
|
|
37278
|
+
...replaceMembers ? { replaceMembers } : {},
|
|
37279
|
+
query: querySource,
|
|
37280
|
+
sourceRepo,
|
|
37281
|
+
skipExisting: flags["skip-existing"],
|
|
37282
|
+
message: flags.message,
|
|
37283
|
+
committer: flags.committer
|
|
37284
|
+
}) : await ctx.client.collection.create(org, repo, {
|
|
37285
|
+
type,
|
|
37286
|
+
name: flags.name,
|
|
37287
|
+
members,
|
|
37288
|
+
...flags.from ? { from: flags.from } : {},
|
|
37289
|
+
...add.length > 0 ? { add } : {},
|
|
37290
|
+
...remove.length > 0 ? { remove } : {},
|
|
37291
|
+
...replaceMembers ? { replaceMembers } : {},
|
|
37292
|
+
query: querySource,
|
|
37293
|
+
skipExisting: flags["skip-existing"],
|
|
37294
|
+
message: flags.message,
|
|
37295
|
+
committer: flags.committer
|
|
37296
|
+
}) : await ctx.client.collection.create(org, repo, {
|
|
37297
|
+
type,
|
|
37298
|
+
name: flags.name,
|
|
37299
|
+
members,
|
|
37300
|
+
...flags.from ? { from: flags.from } : {},
|
|
37301
|
+
...add.length > 0 ? { add } : {},
|
|
37302
|
+
...remove.length > 0 ? { remove } : {},
|
|
37303
|
+
...replaceMembers ? { replaceMembers } : {},
|
|
37304
|
+
skipExisting: flags["skip-existing"],
|
|
37305
|
+
message: flags.message,
|
|
37306
|
+
committer: flags.committer
|
|
37307
|
+
});
|
|
37308
|
+
writeOutput(ctx, result, () => renderMutation(ctx, result));
|
|
37309
|
+
};
|
|
37310
|
+
var handleCollectionMembers = async (ctx, { flags, args }) => {
|
|
37311
|
+
const wref = args[0];
|
|
37312
|
+
if (!wref) {
|
|
37313
|
+
usageError("Usage: wh collection members <wref> [--limit N] [--cursor TOKEN] [--all]", "wh collection members Set/audited --all");
|
|
37314
|
+
}
|
|
37315
|
+
if (flags.cursor && !flags.limit) {
|
|
37316
|
+
usageError("Usage: wh collection members <wref> --limit N --cursor TOKEN", "wh collection members Set/audited --limit 50 --cursor <token>");
|
|
37317
|
+
}
|
|
37318
|
+
const { org, repo } = parseCollectionReadRepo(ctx, [wref]);
|
|
37319
|
+
const boundedLimit = Math.min(flags.limit ?? DEFAULT_PAGE_LIMIT, MAX_PAGE_LIMIT);
|
|
37320
|
+
const pageLimit = flags.all ? Math.min(flags.limit ?? AUTO_PAGE_LIMIT, MAX_PAGE_LIMIT) : boundedLimit;
|
|
37321
|
+
if (flags.all) {
|
|
37322
|
+
const items = [];
|
|
37323
|
+
let cursor = flags.cursor;
|
|
37324
|
+
let snapshotVersion = flags.version;
|
|
37325
|
+
let firstPage;
|
|
37326
|
+
while (true) {
|
|
37327
|
+
const page = await ctx.client.collection.members(org, repo, wref, {
|
|
37328
|
+
version: snapshotVersion,
|
|
37329
|
+
limit: pageLimit,
|
|
37330
|
+
cursor
|
|
37331
|
+
});
|
|
37332
|
+
firstPage ??= {
|
|
37333
|
+
type: page.type,
|
|
37334
|
+
wref: page.wref,
|
|
37335
|
+
version: page.version
|
|
37336
|
+
};
|
|
37337
|
+
items.push(...page.items);
|
|
37338
|
+
snapshotVersion ??= page.version;
|
|
37339
|
+
if (!page.nextCursor)
|
|
37340
|
+
break;
|
|
37341
|
+
cursor = page.nextCursor;
|
|
37342
|
+
}
|
|
37343
|
+
writeCollectionMembersOutput(ctx, {
|
|
37344
|
+
type: firstPage?.type ?? "set",
|
|
37345
|
+
wref: firstPage?.wref ?? wref,
|
|
37346
|
+
version: snapshotVersion ?? firstPage?.version ?? flags.version ?? 1,
|
|
37347
|
+
items,
|
|
37348
|
+
nextCursor: undefined
|
|
37349
|
+
}, { limit: pageLimit, nextCursor: null });
|
|
37350
|
+
return;
|
|
37351
|
+
}
|
|
37352
|
+
const result = await ctx.client.collection.members(org, repo, wref, {
|
|
37353
|
+
version: flags.version,
|
|
37354
|
+
limit: boundedLimit,
|
|
37355
|
+
cursor: flags.cursor
|
|
37356
|
+
});
|
|
37357
|
+
if (result.nextCursor) {
|
|
37358
|
+
emitPartialPageHint(ctx, result.items.length, result.nextCursor, boundedLimit);
|
|
37359
|
+
}
|
|
37360
|
+
writeCollectionMembersOutput(ctx, result, {
|
|
37361
|
+
limit: boundedLimit,
|
|
37362
|
+
nextCursor: result.nextCursor ?? null
|
|
37363
|
+
});
|
|
37364
|
+
};
|
|
37365
|
+
function writeCollectionMembersOutput(ctx, result, page) {
|
|
37366
|
+
if (ctx.format === "json") {
|
|
37367
|
+
const envelope = pageEnvelope(result.items, page);
|
|
37368
|
+
printJson(ctx.out, {
|
|
37369
|
+
type: result.type,
|
|
37370
|
+
wref: result.wref,
|
|
37371
|
+
version: result.version,
|
|
37372
|
+
items: result.items,
|
|
37373
|
+
page: envelope.page
|
|
37374
|
+
});
|
|
37375
|
+
return;
|
|
37376
|
+
}
|
|
37377
|
+
if (ctx.format === "jsonl") {
|
|
37378
|
+
printJsonl(ctx.out, result.items);
|
|
37379
|
+
return;
|
|
37380
|
+
}
|
|
37381
|
+
renderMembers(ctx, result);
|
|
37382
|
+
}
|
|
37383
|
+
var handleCollectionContains = async (ctx, { flags, args }) => {
|
|
37384
|
+
const wref = args[0];
|
|
37385
|
+
if (!wref) {
|
|
37386
|
+
usageError("Usage: wh collection contains <wref> <member...>", "wh collection contains Set/audited Location/a Location/b");
|
|
37387
|
+
}
|
|
37388
|
+
const members = await readMembersFromSources(ctx, {
|
|
37389
|
+
positionals: args.slice(1),
|
|
37390
|
+
members: flags.members,
|
|
37391
|
+
file: flags.file,
|
|
37392
|
+
stdin: flags.stdin,
|
|
37393
|
+
wrefField: flags["wref-field"],
|
|
37394
|
+
label: "collection contains members"
|
|
37395
|
+
});
|
|
37396
|
+
requireMembers(members, "wh collection contains Set/audited Location/a Location/b");
|
|
37397
|
+
const { org, repo } = parseCollectionReadRepo(ctx, [wref]);
|
|
37398
|
+
const result = await ctx.client.collection.contains(org, repo, wref, members, {
|
|
37399
|
+
version: flags.version,
|
|
37400
|
+
position: flags.position
|
|
37401
|
+
});
|
|
37402
|
+
writeOutput(ctx, result, () => renderContains(ctx, result));
|
|
37403
|
+
};
|
|
37404
|
+
var handleCollectionDiff = async (ctx, { flags, args }) => {
|
|
37405
|
+
const [leftWref, rightWref] = args;
|
|
37406
|
+
if (!leftWref || !rightWref) {
|
|
37407
|
+
usageError("Usage: wh collection diff <left-wref> <right-wref> [--mode auto|membership|ordered]", "wh collection diff Set/yesterday Set/today --mode membership");
|
|
37408
|
+
}
|
|
37409
|
+
const { org, repo } = parseCollectionReadRepo(ctx, [leftWref, rightWref]);
|
|
37410
|
+
const result = await ctx.client.collection.diff(org, repo, leftWref, rightWref, {
|
|
37411
|
+
leftVersion: flags["left-version"],
|
|
37412
|
+
rightVersion: flags["right-version"],
|
|
37413
|
+
mode: validateDiffMode(flags.mode)
|
|
37414
|
+
});
|
|
37415
|
+
writeOutput(ctx, result, () => renderDiff(ctx, result));
|
|
37416
|
+
};
|
|
37417
|
+
var handleCollectionRevise = async (ctx, { flags, args }) => {
|
|
37418
|
+
const wref = args[0];
|
|
37419
|
+
if (!wref) {
|
|
37420
|
+
usageError('Usage: wh collection revise <named-wref> --file members.txt -m "message"', 'wh collection revise Set/audited --file members.txt -m "refresh audit set"');
|
|
37421
|
+
}
|
|
37422
|
+
const add = parseMemberList(flags.add);
|
|
37423
|
+
const remove = parseMemberList(flags.remove);
|
|
37424
|
+
if ((add.length > 0 || remove.length > 0) && (flags.members || flags.file || flags.stdin)) {
|
|
37425
|
+
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"');
|
|
37426
|
+
}
|
|
37427
|
+
const members = await readMembersFromSources(ctx, {
|
|
37428
|
+
members: flags.members,
|
|
37429
|
+
file: add.length > 0 || remove.length > 0 ? undefined : flags.file,
|
|
37430
|
+
stdin: add.length > 0 || remove.length > 0 ? undefined : flags.stdin,
|
|
37431
|
+
wrefField: flags["wref-field"],
|
|
37432
|
+
label: "replacement members"
|
|
37433
|
+
});
|
|
37434
|
+
const querySource = collectionQuerySourceFromFlags(flags);
|
|
37435
|
+
const sourceRepo = parseSourceRepoFlag(flags["source-repo"]);
|
|
37436
|
+
requireQuerySourceForSourceRepo(sourceRepo, querySource, 'wh collection revise Set/audited --source-repo data/nc-voters --shape Voter -m "refresh audit set"');
|
|
37437
|
+
requireSelectorAnchorForQuerySource(querySource, 'wh collection revise Set/audited --match "Location/*" -m "refresh audit set"');
|
|
37438
|
+
if (sourceRepo && members.length > 0) {
|
|
37439
|
+
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"');
|
|
37440
|
+
}
|
|
37441
|
+
if ((add.length > 0 || remove.length > 0) && (members.length > 0 || hasCollectionQuerySource2(querySource))) {
|
|
37442
|
+
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"');
|
|
37443
|
+
}
|
|
37444
|
+
const targetType = collectionTypeFromWref2(wref);
|
|
37445
|
+
if (hasCollectionQuerySource2(querySource) && targetType && targetType !== "set") {
|
|
37446
|
+
usageError("Selector-backed revise requires a Set/<name> target wref", 'wh collection revise Set/audited --match "Location/*" -m "refresh audit set"');
|
|
37447
|
+
}
|
|
37448
|
+
const { org, repo } = parseOrgRepo(getRepoRef(ctx), ctx.config);
|
|
37449
|
+
const queryBacked = hasCollectionQuerySource2(querySource);
|
|
37450
|
+
if (!queryBacked && add.length === 0 && remove.length === 0) {
|
|
37451
|
+
requireMembers(members, 'wh collection revise Set/audited --file members.txt -m "refresh audit set"');
|
|
37452
|
+
}
|
|
37453
|
+
const result = queryBacked ? sourceRepo ? await ctx.client.collection.revise(org, repo, wref, {
|
|
37454
|
+
query: querySource,
|
|
37455
|
+
sourceRepo,
|
|
37456
|
+
message: flags.message,
|
|
37457
|
+
committer: flags.committer
|
|
37458
|
+
}) : await ctx.client.collection.revise(org, repo, wref, {
|
|
37459
|
+
members,
|
|
37460
|
+
query: querySource,
|
|
37461
|
+
message: flags.message,
|
|
37462
|
+
committer: flags.committer
|
|
37463
|
+
}) : await ctx.client.collection.revise(org, repo, wref, {
|
|
37464
|
+
members,
|
|
37465
|
+
...add.length > 0 ? { add } : {},
|
|
37466
|
+
...remove.length > 0 ? { remove } : {},
|
|
37467
|
+
message: flags.message,
|
|
37468
|
+
committer: flags.committer
|
|
37469
|
+
});
|
|
37470
|
+
writeOutput(ctx, result, () => renderMutation(ctx, result));
|
|
37471
|
+
};
|
|
37472
|
+
var handleCollectionStats = async (ctx, { flags, args }) => {
|
|
37473
|
+
const wref = args[0];
|
|
37474
|
+
if (!wref) {
|
|
37475
|
+
usageError("Usage: wh collection stats <wref>", "wh collection stats Set/audited");
|
|
37476
|
+
}
|
|
37477
|
+
const { org, repo } = parseCollectionReadRepo(ctx, [wref]);
|
|
37478
|
+
const result = await ctx.client.collection.stats(org, repo, wref, {
|
|
37479
|
+
version: flags.version
|
|
37480
|
+
});
|
|
37481
|
+
writeOutput(ctx, result, () => renderStats(ctx, result));
|
|
37482
|
+
};
|
|
37483
|
+
var COLLECTION_DOMAIN = defineDomain({
|
|
37484
|
+
name: "collection",
|
|
37485
|
+
summary: "Create, inspect, compare, and revise WarmHub collections (Pair, Set, List).",
|
|
37486
|
+
group: "resource",
|
|
37487
|
+
verbs: {
|
|
37488
|
+
create: {
|
|
37489
|
+
summary: "Create a collection thing from explicit members or a set selector",
|
|
37490
|
+
args: "",
|
|
37491
|
+
flags: collectionCreateFlags,
|
|
37492
|
+
examples: [
|
|
37493
|
+
'wh collection create --type set --name audited --members Location/a,Location/b -m "audit snapshot"',
|
|
37494
|
+
'wh collection create --type set --name voters --match "Voter/*" -m "voter snapshot"',
|
|
37495
|
+
'wh collection create --type set --name wake-voters --shape Voter --where state=NC --where county=Wake -m "snapshot Wake County voters"',
|
|
37496
|
+
'wh collection create --type set --name today --from Set/yesterday --add Location/c --remove Location/a -m "delta"'
|
|
37497
|
+
],
|
|
37498
|
+
handler: handleCollectionCreate
|
|
37499
|
+
},
|
|
37500
|
+
revise: {
|
|
37501
|
+
summary: "Revise a named collection by replacement, selector, or set delta",
|
|
37502
|
+
args: "<named-wref>",
|
|
37503
|
+
flags: collectionReviseFlags,
|
|
37504
|
+
examples: [
|
|
37505
|
+
'wh collection revise Set/audited --file members.txt -m "refresh audit set"',
|
|
37506
|
+
'wh collection revise Set/audited --match "Location/*" -m "refresh audit set"',
|
|
37507
|
+
'wh collection revise Set/audited --add Location/c --remove Location/a -m "delta"'
|
|
37508
|
+
],
|
|
37509
|
+
handler: handleCollectionRevise
|
|
37510
|
+
},
|
|
37511
|
+
members: {
|
|
37512
|
+
summary: "List collection members with pagination",
|
|
37513
|
+
args: "<wref>",
|
|
37514
|
+
flags: collectionMembersFlags,
|
|
37515
|
+
examples: ["wh collection members Set/audited --all"],
|
|
37516
|
+
handler: handleCollectionMembers
|
|
37517
|
+
},
|
|
37518
|
+
contains: {
|
|
37519
|
+
summary: "Check collection membership for one or more wrefs",
|
|
37520
|
+
args: "<wref> <member...>",
|
|
37521
|
+
flags: collectionContainsFlags,
|
|
37522
|
+
examples: ["wh collection contains Set/audited Location/a Location/b"],
|
|
37523
|
+
handler: handleCollectionContains
|
|
37524
|
+
},
|
|
37525
|
+
diff: {
|
|
37526
|
+
summary: "Compare two collections by membership or order",
|
|
37527
|
+
args: "<left-wref> <right-wref>",
|
|
37528
|
+
flags: collectionDiffFlags,
|
|
37529
|
+
examples: [
|
|
37530
|
+
"wh collection diff Set/yesterday Set/today --mode membership"
|
|
37531
|
+
],
|
|
37532
|
+
handler: handleCollectionDiff
|
|
37533
|
+
},
|
|
37534
|
+
stats: {
|
|
37535
|
+
summary: "Summarize collection size and identity",
|
|
37536
|
+
args: "<wref>",
|
|
37537
|
+
flags: collectionStatsFlags,
|
|
37538
|
+
examples: ["wh collection stats Set/audited"],
|
|
37539
|
+
handler: handleCollectionStats
|
|
37540
|
+
}
|
|
37541
|
+
}
|
|
37542
|
+
});
|
|
37543
|
+
|
|
36583
37544
|
// ../../packages/warmhub-cli/src/domains/commit-submit-flags.ts
|
|
36584
37545
|
var createFlags3 = {
|
|
36585
37546
|
ops: flag.string({
|
|
@@ -36644,7 +37605,10 @@ var createFlags3 = {
|
|
|
36644
37605
|
multiple: true
|
|
36645
37606
|
}),
|
|
36646
37607
|
type: flag.string({
|
|
36647
|
-
description: "Collection type: pair,
|
|
37608
|
+
description: "Collection type: pair, set, list"
|
|
37609
|
+
}),
|
|
37610
|
+
name: flag.string({
|
|
37611
|
+
description: "Collection name for --type shorthand"
|
|
36648
37612
|
}),
|
|
36649
37613
|
members: flag.string({
|
|
36650
37614
|
description: "Collection members (comma-separated wrefs)"
|
|
@@ -36789,32 +37753,12 @@ function emitTemplateHint(ctx, operationType) {
|
|
|
36789
37753
|
const assertionArgs = operationType === "add" ? "--kind assertion --about <Target/FILL_IN>" : "--kind assertion";
|
|
36790
37754
|
ctx.err(`Template note: shapes define payload fields. To scaffold an assertion, rerun with ${assertionArgs}.`);
|
|
36791
37755
|
}
|
|
36792
|
-
var COLLECTION_ABOUT_PREFIX_RE = /^(pair|
|
|
37756
|
+
var COLLECTION_ABOUT_PREFIX_RE = /^(pair|set|list):(.*)$/;
|
|
36793
37757
|
function parseCollectionAboutFlag(raw) {
|
|
36794
37758
|
const match = COLLECTION_ABOUT_PREFIX_RE.exec(raw);
|
|
36795
37759
|
if (!match)
|
|
36796
37760
|
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 };
|
|
37761
|
+
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
37762
|
}
|
|
36819
37763
|
var handleTemplate = async (ctx, { flags, args }) => {
|
|
36820
37764
|
const shapeNames = args;
|
|
@@ -37618,7 +38562,7 @@ var handleSubmit = async (ctx, { flags, args }) => {
|
|
|
37618
38562
|
throw new CliError(2 /* UserInput */, "USER_INPUT", `Invalid --kind "${k}". Must be one of: ${validKinds.join(", ")}`);
|
|
37619
38563
|
}
|
|
37620
38564
|
}
|
|
37621
|
-
const validCollectionTypes = ["pair", "
|
|
38565
|
+
const validCollectionTypes = ["pair", "set", "list"];
|
|
37622
38566
|
if (flags.type && !validCollectionTypes.includes(flags.type)) {
|
|
37623
38567
|
throw new CliError(2 /* UserInput */, "USER_INPUT", `Invalid --type "${flags.type}". Must be one of: ${validCollectionTypes.join(", ")}`);
|
|
37624
38568
|
}
|
|
@@ -37650,11 +38594,14 @@ var handleSubmit = async (ctx, { flags, args }) => {
|
|
|
37650
38594
|
if (streamInput) {
|
|
37651
38595
|
operations = [];
|
|
37652
38596
|
} else if (collectionType) {
|
|
38597
|
+
if (!flags.name) {
|
|
38598
|
+
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");
|
|
38599
|
+
}
|
|
37653
38600
|
if (!flags.members) {
|
|
37654
|
-
usageError("Usage: wh commit submit --type <pair|
|
|
38601
|
+
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
38602
|
}
|
|
37656
38603
|
const members = flags.members.split(",").map((m) => m.trim()).filter(Boolean);
|
|
37657
|
-
const arityMap = { pair: 2
|
|
38604
|
+
const arityMap = { pair: 2 };
|
|
37658
38605
|
const expected = arityMap[collectionType];
|
|
37659
38606
|
if (expected && members.length !== expected) {
|
|
37660
38607
|
throw new CliError(2 /* UserInput */, "USER_INPUT", `${collectionType} requires exactly ${expected} members, got ${members.length}`);
|
|
@@ -37667,6 +38614,7 @@ var handleSubmit = async (ctx, { flags, args }) => {
|
|
|
37667
38614
|
operation: "add",
|
|
37668
38615
|
kind: "collection",
|
|
37669
38616
|
type: collectionType,
|
|
38617
|
+
name: flags.name,
|
|
37670
38618
|
members
|
|
37671
38619
|
}
|
|
37672
38620
|
];
|
|
@@ -37817,8 +38765,8 @@ var COMMIT_DOMAIN = defineDomain({
|
|
|
37817
38765
|
`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
38766
|
'wh commit submit --file dataset.jsonl --stream-id bulk-2026-06-04 --skip-existing --progress -m "bulk stream"',
|
|
37819
38767
|
"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"'
|
|
38768
|
+
"wh commit submit --type pair --name location-distance --members Location/a,Location/b",
|
|
38769
|
+
'wh commit submit --type set --name active-locations --members Location/a,Location/b,Location/c -m "Create location set"'
|
|
37822
38770
|
],
|
|
37823
38771
|
notes: [
|
|
37824
38772
|
"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 +38780,7 @@ var COMMIT_DOMAIN = defineDomain({
|
|
|
37832
38780
|
import {
|
|
37833
38781
|
existsSync as existsSync7,
|
|
37834
38782
|
mkdirSync as mkdirSync6,
|
|
37835
|
-
readFileSync as
|
|
38783
|
+
readFileSync as readFileSync7,
|
|
37836
38784
|
renameSync as renameSync3,
|
|
37837
38785
|
rmSync as rmSync4,
|
|
37838
38786
|
writeFileSync as writeFileSync6
|
|
@@ -37868,7 +38816,7 @@ function loadInstallSnapshotCacheRaw(repoSlug) {
|
|
|
37868
38816
|
if (!path2 || !existsSync7(path2))
|
|
37869
38817
|
return null;
|
|
37870
38818
|
try {
|
|
37871
|
-
const raw =
|
|
38819
|
+
const raw = readFileSync7(path2, "utf-8");
|
|
37872
38820
|
return JSON.parse(raw);
|
|
37873
38821
|
} catch {
|
|
37874
38822
|
return null;
|
|
@@ -38638,7 +39586,7 @@ function formatReservedNameWarning(name) {
|
|
|
38638
39586
|
}
|
|
38639
39587
|
|
|
38640
39588
|
// ../../packages/warmhub-cli/src/manifest/parser.ts
|
|
38641
|
-
import { existsSync as existsSync8, readFileSync as
|
|
39589
|
+
import { existsSync as existsSync8, readFileSync as readFileSync8 } from "node:fs";
|
|
38642
39590
|
import { resolve } from "node:path";
|
|
38643
39591
|
function parseComponentPackage(dirPath) {
|
|
38644
39592
|
const rootDir = resolve(dirPath);
|
|
@@ -38651,7 +39599,7 @@ function parseComponentPackage(dirPath) {
|
|
|
38651
39599
|
}
|
|
38652
39600
|
let componentRaw;
|
|
38653
39601
|
try {
|
|
38654
|
-
componentRaw = JSON.parse(
|
|
39602
|
+
componentRaw = JSON.parse(readFileSync8(componentJsonPath, "utf-8"));
|
|
38655
39603
|
} catch (err) {
|
|
38656
39604
|
errors.push(`Failed to parse warmhub/component.json: ${err instanceof Error ? err.message : String(err)}`);
|
|
38657
39605
|
return { ok: false, errors, warnings };
|
|
@@ -38666,7 +39614,7 @@ function parseComponentPackage(dirPath) {
|
|
|
38666
39614
|
}
|
|
38667
39615
|
let manifestRaw;
|
|
38668
39616
|
try {
|
|
38669
|
-
manifestRaw = JSON.parse(
|
|
39617
|
+
manifestRaw = JSON.parse(readFileSync8(manifestJsonPath, "utf-8"));
|
|
38670
39618
|
} catch (err) {
|
|
38671
39619
|
errors.push(`Failed to parse warmhub/manifest.json: ${err instanceof Error ? err.message : String(err)}`);
|
|
38672
39620
|
return { ok: false, errors, warnings };
|
|
@@ -38867,7 +39815,7 @@ function formatLifecycleUrl(url, colors) {
|
|
|
38867
39815
|
}
|
|
38868
39816
|
|
|
38869
39817
|
// ../../packages/warmhub-cli/src/domains/component-utils.ts
|
|
38870
|
-
import { readFileSync as
|
|
39818
|
+
import { readFileSync as readFileSync9 } from "node:fs";
|
|
38871
39819
|
function isRegisteredComponentSource(source) {
|
|
38872
39820
|
return /^[a-z0-9-]+\/[a-z0-9-]+$/.test(source);
|
|
38873
39821
|
}
|
|
@@ -38907,7 +39855,7 @@ function resolveMintedTokensFlag(args) {
|
|
|
38907
39855
|
function readManifestArg(path2) {
|
|
38908
39856
|
let raw;
|
|
38909
39857
|
try {
|
|
38910
|
-
raw =
|
|
39858
|
+
raw = readFileSync9(path2, "utf8");
|
|
38911
39859
|
} catch {
|
|
38912
39860
|
throw new CliError(2 /* UserInput */, "USER_INPUT", `Cannot read manifest file: ${path2}`, undefined, "Pass --manifest <path to warmhub/manifest.json>");
|
|
38913
39861
|
}
|
|
@@ -41526,7 +42474,7 @@ wh assertion create --shape ShapeName --about Target/name --name my-assertion --
|
|
|
41526
42474
|
wh thing list --repo org/repo # all things at HEAD
|
|
41527
42475
|
wh thing view Shape/name --repo org/repo # inspect a thing
|
|
41528
42476
|
wh thing query --shape MyShape --repo org/repo # find things by shape
|
|
41529
|
-
wh thing about Shape/name --repo org/repo # assertions about
|
|
42477
|
+
wh thing about Shape/name --repo org/repo # assertions about thing/shape
|
|
41530
42478
|
wh assertion list --repo org/repo # all assertions at HEAD
|
|
41531
42479
|
wh thing history Shape/name --repo org/repo # version history
|
|
41532
42480
|
|
|
@@ -41538,17 +42486,16 @@ cat wrefs.txt | wh thing view --format jsonl # one JSON line per *deduped
|
|
|
41538
42486
|
|
|
41539
42487
|
## Wref Quick Reference
|
|
41540
42488
|
|
|
41541
|
-
|
|
41542
|
-
|
|
41543
|
-
|
|
41544
|
-
- Example: \`Player/player-$1\` + about \`Player/player-#1\` → \`Player/player-a1b2c3d4e5f6a7b8\`
|
|
42489
|
+
Write operations use explicit names and explicit wrefs. To connect operations
|
|
42490
|
+
inside one commit, create the first thing with a deterministic name and point
|
|
42491
|
+
later operations at that wref.
|
|
41545
42492
|
|
|
41546
42493
|
## Command Reference
|
|
41547
42494
|
|
|
41548
42495
|
**Global flags**: \`--repo\`, \`--format\`, \`--json\`, \`--live\`
|
|
41549
42496
|
### thing — Thing operations
|
|
41550
42497
|
- \`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
|
|
42498
|
+
- \`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.
|
|
41552
42499
|
- \`wh thing history [wref] [--shape] [--about] [--include-retracted]\` — Version history
|
|
41553
42500
|
- \`wh thing resolve <wref>\` — Resolve wref
|
|
41554
42501
|
- \`wh thing create <name|Shape/name> --data <json-object> [--shape] [--message] [--committer]\` — Create
|
|
@@ -41557,7 +42504,7 @@ cat wrefs.txt | wh thing view --format jsonl # one JSON line per *deduped
|
|
|
41557
42504
|
- \`wh thing query [--shape] [--kind] [--about] [--match]\` — Query by filters
|
|
41558
42505
|
- \`wh thing search <query> [--shape] [--kind] [--about] [--mode]\` — Search text
|
|
41559
42506
|
- \`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
|
|
42507
|
+
- \`wh thing refs <wref> [--inbound] [--outbound] [--field]\` — Show field references; use \`wh thing about\` for assertions about things/shapes
|
|
41561
42508
|
- \`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
42509
|
|
|
41563
42510
|
### commit — Write operations
|
|
@@ -41643,12 +42590,12 @@ cat wrefs.txt | wh thing view --format jsonl # one JSON line per *deduped
|
|
|
41643
42590
|
wh thing list --repo org/repo # see all things in HEAD
|
|
41644
42591
|
wh thing view Shape/name --repo org/repo # inspect a specific thing
|
|
41645
42592
|
wh thing history Shape/name --repo org/repo # inspect version history
|
|
41646
|
-
wh thing about Shape/name # assertions about
|
|
42593
|
+
wh thing about Shape/name # assertions about thing/shape
|
|
41647
42594
|
\`\`\`
|
|
41648
42595
|
|
|
41649
42596
|
**Create an assertion** (most common write):
|
|
41650
42597
|
\`\`\`bash
|
|
41651
|
-
# --about takes a wref
|
|
42598
|
+
# --about takes a target wref: Shape/name thing, or Shape itself.
|
|
41652
42599
|
wh assertion create --shape MyShape --about TargetShape/target-name \\
|
|
41653
42600
|
--name my-assertion --data '{"field_a":1,"field_b":"value"}' --repo org/repo
|
|
41654
42601
|
# Output includes per-operation status; relay failures when present.
|
|
@@ -41677,17 +42624,15 @@ wh commit submit --file ops.jsonl --stream-id "$ID" --chunk-size 5000 \\
|
|
|
41677
42624
|
# --chunk-size: ops per append chunk (default 1000, max 10000); chunk≈1 is ~60× slower
|
|
41678
42625
|
# --skip-existing: skips already-written add ops (drops per-row read-before-write)
|
|
41679
42626
|
# Add-stream restart: rerun the WHOLE file with the SAME --stream-id.
|
|
41680
|
-
# Fixed-name adds are idempotent via --skip-existing
|
|
41681
|
-
#
|
|
41682
|
-
#
|
|
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.
|
|
42627
|
+
# Fixed-name adds are idempotent via --skip-existing. Mid-stream resume is not
|
|
42628
|
+
# a CLI mode. Mixed revise/retract JSONL streams are not full-rerun safe after
|
|
42629
|
+
# an ambiguous append; inspect repo state and reconcile explicitly.
|
|
41685
42630
|
\`\`\`
|
|
41686
42631
|
|
|
41687
42632
|
**Create collections:**
|
|
41688
42633
|
\`\`\`bash
|
|
41689
|
-
wh commit submit --type pair --members Location/a,Location/b --repo org/repo
|
|
41690
|
-
wh assertion create --shape Distance --about
|
|
42634
|
+
wh commit submit --type pair --name location-distance --members Location/a,Location/b --repo org/repo
|
|
42635
|
+
wh assertion create --shape Distance --about Pair/location-distance --data '{"value":5}' --repo org/repo
|
|
41691
42636
|
\`\`\`
|
|
41692
42637
|
|
|
41693
42638
|
**Modify data:**
|
|
@@ -41777,8 +42722,7 @@ var wrefSyntax = {
|
|
|
41777
42722
|
"GameState/round-1/state"
|
|
41778
42723
|
],
|
|
41779
42724
|
canonicalFormat: "wh:org/repo/Shape/name",
|
|
41780
|
-
versionModifiers: ["@HEAD", "@vN", "@ALL"]
|
|
41781
|
-
batchTokens: { allocate: "$N", reference: "#N" }
|
|
42725
|
+
versionModifiers: ["@HEAD", "@vN", "@ALL"]
|
|
41782
42726
|
};
|
|
41783
42727
|
var handlePrime = async (ctx) => {
|
|
41784
42728
|
writeOutput(ctx, {
|
|
@@ -44102,7 +45046,7 @@ var TOKEN_DOMAIN = defineDomain({
|
|
|
44102
45046
|
});
|
|
44103
45047
|
|
|
44104
45048
|
// ../../packages/warmhub-cli/src/update-check-cache.ts
|
|
44105
|
-
import { mkdirSync as mkdirSync7, readFileSync as
|
|
45049
|
+
import { mkdirSync as mkdirSync7, readFileSync as readFileSync10, writeFileSync as writeFileSync7 } from "node:fs";
|
|
44106
45050
|
import { homedir as homedir5 } from "node:os";
|
|
44107
45051
|
import { dirname as dirname7, resolve as resolve3 } from "node:path";
|
|
44108
45052
|
|
|
@@ -44171,7 +45115,7 @@ var WH_CACHE_PACKAGE_NAME = WH_CLI_PACKAGE_NAME;
|
|
|
44171
45115
|
var cachePath = (homePath) => resolve3(homePath, ".warmhub", "cli", "update-check.json");
|
|
44172
45116
|
var readCache = (homePath) => {
|
|
44173
45117
|
try {
|
|
44174
|
-
return JSON.parse(
|
|
45118
|
+
return JSON.parse(readFileSync10(cachePath(homePath), "utf8"));
|
|
44175
45119
|
} catch {
|
|
44176
45120
|
return;
|
|
44177
45121
|
}
|
|
@@ -44195,7 +45139,7 @@ var markUpdateNoticeShown = ({
|
|
|
44195
45139
|
|
|
44196
45140
|
// ../../packages/warmhub-cli/src/domains/update-install.ts
|
|
44197
45141
|
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
44198
|
-
import { existsSync as existsSync9, readFileSync as
|
|
45142
|
+
import { existsSync as existsSync9, readFileSync as readFileSync11, realpathSync } from "node:fs";
|
|
44199
45143
|
import { homedir as homedir6 } from "node:os";
|
|
44200
45144
|
import { dirname as dirname8, resolve as resolve4 } from "node:path";
|
|
44201
45145
|
var DEV_INSTALL_PACKAGE_SEARCH_DEPTH = 8;
|
|
@@ -44345,7 +45289,7 @@ var isDevInstall = (scriptPath) => {
|
|
|
44345
45289
|
for (let i = 0;i < DEV_INSTALL_PACKAGE_SEARCH_DEPTH; i += 1) {
|
|
44346
45290
|
const pkgPath = resolve4(dir, "package.json");
|
|
44347
45291
|
try {
|
|
44348
|
-
const pkg = JSON.parse(
|
|
45292
|
+
const pkg = JSON.parse(readFileSync11(pkgPath, "utf8"));
|
|
44349
45293
|
if (pkg.name === "@warmhub/cli") {
|
|
44350
45294
|
if (pkg.private === true)
|
|
44351
45295
|
return true;
|
|
@@ -44631,6 +45575,7 @@ function registerAllDomains(registry2) {
|
|
|
44631
45575
|
registry2.register(INIT_DOMAIN);
|
|
44632
45576
|
registry2.register(REPO_DOMAIN);
|
|
44633
45577
|
registry2.register(THING_DOMAIN);
|
|
45578
|
+
registry2.register(COLLECTION_DOMAIN);
|
|
44634
45579
|
registry2.register(COMMIT_DOMAIN);
|
|
44635
45580
|
registry2.register(ASSERTION_DOMAIN);
|
|
44636
45581
|
registry2.register(SHAPE_DOMAIN);
|
|
@@ -45753,7 +46698,7 @@ function resolveLogLevel(flags, env) {
|
|
|
45753
46698
|
// package.json
|
|
45754
46699
|
var package_default3 = {
|
|
45755
46700
|
name: "@warmhub/cli",
|
|
45756
|
-
version: "0.
|
|
46701
|
+
version: "0.68.0",
|
|
45757
46702
|
private: false,
|
|
45758
46703
|
type: "module",
|
|
45759
46704
|
description: "The wh CLI for WarmHub — create repos, commit and query data, and compound knowledge with your AI agents.",
|
|
@@ -46408,4 +47353,4 @@ if (!updateCheckSuppressedByArgv && shouldRunUpdateCheck(updateEligibility)) {
|
|
|
46408
47353
|
var interceptedExitCode = await maybeHandleComponentShellBoundary(dispatchArgv);
|
|
46409
47354
|
process.exitCode = interceptedExitCode === undefined ? await runCli(dispatchArgv, { version: package_default3.version }) : interceptedExitCode;
|
|
46410
47355
|
|
|
46411
|
-
//# debugId=
|
|
47356
|
+
//# debugId=201635543D774B8564756E2164756E21
|