@warmhub/cli 0.79.1 → 0.81.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.
Files changed (2) hide show
  1. package/dist/wh.js +835 -662
  2. package/package.json +1 -1
package/dist/wh.js CHANGED
@@ -19146,6 +19146,31 @@ var import_usingCtx = __toESM(require_usingCtx(), 1);
19146
19146
  var import_awaitAsyncGenerator = __toESM(require_awaitAsyncGenerator(), 1);
19147
19147
  var import_wrapAsyncGenerator = __toESM(require_wrapAsyncGenerator(), 1);
19148
19148
  var import_objectSpread29 = __toESM(require_objectSpread2(), 1);
19149
+ // ../../packages/rules/src/authority-coverage.ts
19150
+ var EMPTY_COVERAGE = Object.freeze({
19151
+ include: Object.freeze([])
19152
+ });
19153
+ var FULL_REPO_COVERAGE = Object.freeze({
19154
+ include: Object.freeze(["**"])
19155
+ });
19156
+ var EMPTY_COVERAGE_SET = Object.freeze([]);
19157
+ var FULL_REPO_COVERAGE_SET = Object.freeze([
19158
+ Object.freeze([FULL_REPO_COVERAGE])
19159
+ ]);
19160
+ // ../../packages/rules/src/stable-json.ts
19161
+ function stableJson(value) {
19162
+ if (!value || typeof value !== "object") {
19163
+ return JSON.stringify(value);
19164
+ }
19165
+ if (Array.isArray(value)) {
19166
+ return `[${value.map((entry) => stableJson(entry)).join(",")}]`;
19167
+ }
19168
+ const record = value;
19169
+ return `{${Object.keys(record).sort().map((key) => `${JSON.stringify(key)}:${stableJson(record[key])}`).join(",")}}`;
19170
+ }
19171
+ function stableJsonEquals(left, right) {
19172
+ return stableJson(left) === stableJson(right);
19173
+ }
19149
19174
  // ../../packages/rules/src/builtin-shapes.ts
19150
19175
  var BUILTIN_SHAPE_NAMES = [
19151
19176
  "Arc",
@@ -19174,8 +19199,18 @@ var SYNTHESIZED_CONTENT_NAMES = ["LlmsTxt"];
19174
19199
  var isContentShape = (s) => s === "Content";
19175
19200
  var isStoredContentName = (n) => STORED_CONTENT_NAMES.includes(n);
19176
19201
  var isSynthesizedContentName = (n) => SYNTHESIZED_CONTENT_NAMES.includes(n);
19202
+ var BUILTIN_VIEW_SHAPE_NAMES = ["View"];
19203
+ var isViewShape = (name) => BUILTIN_VIEW_SHAPE_NAMES.includes(name);
19204
+ var BUILTIN_LICENSE_SHAPE_NAMES = [
19205
+ "LicenseSubject",
19206
+ "LicenseDeclaration"
19207
+ ];
19208
+ var isLicenseShape = (name) => BUILTIN_LICENSE_SHAPE_NAMES.includes(name);
19209
+ function isRenameableSquattedShape(name) {
19210
+ return isReservedCollectionShape(name) || isViewShape(name) || isLicenseShape(name);
19211
+ }
19177
19212
  function isBuiltinShape(name) {
19178
- return BUILTIN_SHAPE_NAMES.includes(name) || BUILTIN_CONTENT_SHAPE_NAMES.includes(name);
19213
+ return BUILTIN_SHAPE_NAMES.includes(name) || BUILTIN_CONTENT_SHAPE_NAMES.includes(name) || BUILTIN_VIEW_SHAPE_NAMES.includes(name) || BUILTIN_LICENSE_SHAPE_NAMES.includes(name);
19179
19214
  }
19180
19215
  var BUILTIN_SHAPE_DEFS = {
19181
19216
  Arc: {
@@ -19228,9 +19263,76 @@ var BUILTIN_CONTENT_SHAPE_DEFS = {
19228
19263
  description: "Built-in content shape (Readme / Agents / LlmsTxt well-known names)"
19229
19264
  }
19230
19265
  };
19266
+ var VIEW_QUERY_DIALECT = "warmquery/v1";
19267
+ var BUILTIN_VIEW_SHAPE_DEFS = {
19268
+ View: {
19269
+ fields: {
19270
+ dialect: {
19271
+ type: "string",
19272
+ description: `Query dialect stamp (${VIEW_QUERY_DIALECT})`
19273
+ },
19274
+ query: {}
19275
+ },
19276
+ description: "A named, shareable WarmQuery definition bound to durable IDs"
19277
+ }
19278
+ };
19279
+ var BUILTIN_LICENSE_SHAPE_DEFS = {
19280
+ LicenseSubject: {
19281
+ fields: {
19282
+ scope: {
19283
+ type: "string",
19284
+ description: "What portion of the repository is being licensed"
19285
+ },
19286
+ "note?": {
19287
+ type: "string",
19288
+ description: "Optional clarification of the licensed scope"
19289
+ }
19290
+ },
19291
+ description: "A licensable body of work in this repository"
19292
+ },
19293
+ LicenseDeclaration: {
19294
+ fields: {
19295
+ "licenseWref?": {
19296
+ type: "wref",
19297
+ description: "Canonical license reference when one license applies"
19298
+ },
19299
+ spdxIdRaw: {
19300
+ type: "string",
19301
+ description: "Declared SPDX identifier or raw license value"
19302
+ },
19303
+ "spdxExpression?": {
19304
+ type: "string",
19305
+ description: "Full SPDX expression for compound declarations"
19306
+ },
19307
+ "appliesTo?": {
19308
+ type: "string",
19309
+ description: "Kind of work covered by the declaration"
19310
+ },
19311
+ "attributionText?": {
19312
+ type: "string",
19313
+ description: "Attribution text reusers should preserve"
19314
+ },
19315
+ "declaredBy?": {
19316
+ type: "string",
19317
+ description: "Person or organization making the declaration"
19318
+ },
19319
+ "sourceUrl?": {
19320
+ type: "string",
19321
+ description: "Upstream source for the licensing terms"
19322
+ },
19323
+ "note?": {
19324
+ type: "string",
19325
+ description: "Optional declaration caveats or clarification"
19326
+ }
19327
+ },
19328
+ description: "Declares the license of a LicenseSubject"
19329
+ }
19330
+ };
19231
19331
  var ALL_BUILTIN_SHAPE_DEFS = {
19232
19332
  ...BUILTIN_SHAPE_DEFS,
19233
- ...BUILTIN_CONTENT_SHAPE_DEFS
19333
+ ...BUILTIN_CONTENT_SHAPE_DEFS,
19334
+ ...BUILTIN_VIEW_SHAPE_DEFS,
19335
+ ...BUILTIN_LICENSE_SHAPE_DEFS
19234
19336
  };
19235
19337
  // ../../packages/rules/src/client-header.ts
19236
19338
  var CLIENT_HEADER = "X-WarmHub-Client";
@@ -19297,21 +19399,6 @@ function resolveComponentTemplate(value, ctx) {
19297
19399
  });
19298
19400
  }
19299
19401
 
19300
- // ../../packages/rules/src/stable-json.ts
19301
- function stableJson(value) {
19302
- if (!value || typeof value !== "object") {
19303
- return JSON.stringify(value);
19304
- }
19305
- if (Array.isArray(value)) {
19306
- return `[${value.map((entry) => stableJson(entry)).join(",")}]`;
19307
- }
19308
- const record = value;
19309
- return `{${Object.keys(record).sort().map((key) => `${JSON.stringify(key)}:${stableJson(record[key])}`).join(",")}}`;
19310
- }
19311
- function stableJsonEquals(left, right) {
19312
- return stableJson(left) === stableJson(right);
19313
- }
19314
-
19315
19402
  // ../../packages/rules/src/org-activity-events.ts
19316
19403
  var ORG_MEMBER_ADDED_EVENT_TYPE = "org.member_added";
19317
19404
  var ORG_REPO_CREATED_EVENT_TYPE = "org.repo_created";
@@ -20225,19 +20312,6 @@ function validateManifestSemantics(manifest) {
20225
20312
  }
20226
20313
  return findings;
20227
20314
  }
20228
- // ../../packages/rules/src/external-contract.ts
20229
- var FORBIDDEN_EXTERNAL_FIELDS = new Set([
20230
- "_id",
20231
- "_creationTime",
20232
- "repoId",
20233
- "orgId",
20234
- "thingId",
20235
- "shapeThingId",
20236
- "aboutThingId",
20237
- "currentVersionId",
20238
- "createdInCommitId",
20239
- "validatedShapeVersionId"
20240
- ]);
20241
20315
  // ../../packages/rules/src/field-name-safety.ts
20242
20316
  var ESCAPE_DISPLAY_MAX_CHARS = 120;
20243
20317
  var DANGEROUS_FORMAT_CODEPOINTS = new Set([
@@ -20336,487 +20410,149 @@ function joinFieldIdentityPath(...segments) {
20336
20410
  function joinFieldPathWithEscaper(escapeSegment, segments) {
20337
20411
  return segments.map((segment) => typeof segment === "number" ? `[${segment}]` : escapeSegment(segment)).join(".").replace(/\.\[/g, "[");
20338
20412
  }
20339
- // ../../packages/rules/src/permission-scopes.ts
20340
- var PUBLIC_ORG_PERMISSIONS = new Set([
20341
- "org:read",
20342
- "components:read"
20413
+
20414
+ // ../../packages/rules/src/shape-types.ts
20415
+ var BASE_PRIMITIVE_TYPES = [
20416
+ "number",
20417
+ "string",
20418
+ "boolean",
20419
+ "wref",
20420
+ "array"
20421
+ ];
20422
+ var BASE_PRIMITIVE_TYPE_SET = new Set(BASE_PRIMITIVE_TYPES);
20423
+ var VALID_PRIMITIVE_TYPES = new Set([
20424
+ "number",
20425
+ "string",
20426
+ "boolean",
20427
+ "wref",
20428
+ "array",
20429
+ "number?",
20430
+ "string?",
20431
+ "boolean?",
20432
+ "wref?",
20433
+ "array?"
20343
20434
  ]);
20344
- // ../../packages/rules/src/tokens.ts
20345
- 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.";
20346
- var ANY_TOKEN_RE = /[$#]\d+/;
20347
- function hasAnyTokens(s) {
20348
- return ANY_TOKEN_RE.test(s);
20435
+ function isPlainObject(value) {
20436
+ return typeof value === "object" && value !== null && !Array.isArray(value);
20349
20437
  }
20350
-
20351
- // ../../packages/rules/src/preflight-commit.ts
20352
- function preflightCommitDiagnostics(operations, options) {
20353
- const errors = [];
20354
- rejectCommitTokenSyntax(operations, errors);
20355
- illegalOpSequences(operations, errors, options?.checkAddAdd ?? true);
20356
- return errors;
20438
+ var STRING_CONSTRAINT_KEYS = new Set([
20439
+ "minLength",
20440
+ "maxLength",
20441
+ "pattern",
20442
+ "enum"
20443
+ ]);
20444
+ var NUMBER_CONSTRAINT_KEYS = new Set(["minimum", "maximum", "integer"]);
20445
+ var WREF_CONSTRAINT_KEYS = new Set(["shape"]);
20446
+ var ARRAY_CONSTRAINT_KEYS = new Set(["items", "minItems", "maxItems"]);
20447
+ var COMMON_TYPESPEC_KEYS = new Set(["type", "description"]);
20448
+ var VALID_TYPESPEC_KEYS = new Set([
20449
+ ...COMMON_TYPESPEC_KEYS,
20450
+ ...STRING_CONSTRAINT_KEYS,
20451
+ ...NUMBER_CONSTRAINT_KEYS,
20452
+ ...WREF_CONSTRAINT_KEYS,
20453
+ ...ARRAY_CONSTRAINT_KEYS
20454
+ ]);
20455
+ var CONSTRAINT_KEYS_BY_TYPE = {
20456
+ string: STRING_CONSTRAINT_KEYS,
20457
+ number: NUMBER_CONSTRAINT_KEYS,
20458
+ wref: WREF_CONSTRAINT_KEYS,
20459
+ array: ARRAY_CONSTRAINT_KEYS,
20460
+ boolean: new Set
20461
+ };
20462
+ function isTypeSpecObject(value) {
20463
+ if (!isPlainObject(value) || !("type" in value))
20464
+ return false;
20465
+ if (typeof value.type !== "string" || !VALID_PRIMITIVE_TYPES.has(value.type))
20466
+ return false;
20467
+ const baseType = value.type.endsWith("?") ? value.type.slice(0, -1) : value.type;
20468
+ const allowedConstraints = CONSTRAINT_KEYS_BY_TYPE[baseType] ?? new Set;
20469
+ if (!Object.keys(value).every((k) => COMMON_TYPESPEC_KEYS.has(k) || allowedConstraints.has(k)))
20470
+ return false;
20471
+ if ("minLength" in value && typeof value.minLength !== "number")
20472
+ return false;
20473
+ if ("maxLength" in value && typeof value.maxLength !== "number")
20474
+ return false;
20475
+ if ("pattern" in value && typeof value.pattern !== "string")
20476
+ return false;
20477
+ if ("pattern" in value && typeof value.pattern === "string" && VALID_PRIMITIVE_TYPES.has(value.pattern)) {
20478
+ const baseType2 = typeof value.type === "string" && value.type.endsWith("?") ? value.type.slice(0, -1) : value.type;
20479
+ if (baseType2 !== "string")
20480
+ return false;
20481
+ }
20482
+ if ("enum" in value && !Array.isArray(value.enum))
20483
+ return false;
20484
+ if ("minimum" in value && typeof value.minimum !== "number")
20485
+ return false;
20486
+ if ("maximum" in value && typeof value.maximum !== "number")
20487
+ return false;
20488
+ if ("integer" in value && typeof value.integer !== "boolean")
20489
+ return false;
20490
+ if ("shape" in value && typeof value.shape !== "string")
20491
+ return false;
20492
+ if ("shape" in value && typeof value.shape === "string" && VALID_PRIMITIVE_TYPES.has(value.shape)) {
20493
+ const baseType2 = typeof value.type === "string" && value.type.endsWith("?") ? value.type.slice(0, -1) : value.type;
20494
+ if (baseType2 !== "wref")
20495
+ return false;
20496
+ }
20497
+ if ("items" in value && typeof value.items === "number")
20498
+ return false;
20499
+ if ("items" in value && typeof value.items === "boolean")
20500
+ return false;
20501
+ if ("minItems" in value && typeof value.minItems !== "number")
20502
+ return false;
20503
+ if ("maxItems" in value && typeof value.maxItems !== "number")
20504
+ return false;
20505
+ return true;
20357
20506
  }
20358
- function getOpName(op) {
20359
- return op.name;
20507
+ function primitiveTypeSpecFromFieldSpec(fieldType) {
20508
+ if (typeof fieldType === "string" && VALID_PRIMITIVE_TYPES.has(fieldType)) {
20509
+ return fieldType;
20510
+ }
20511
+ if (isTypeSpecObject(fieldType)) {
20512
+ return fieldType.type;
20513
+ }
20514
+ return null;
20360
20515
  }
20361
- function tokenStringFields(op) {
20362
- const fields = [getOpName(op), op.newName];
20363
- if (typeof op.about === "string") {
20364
- fields.push(op.about);
20516
+ function basePrimitiveTypeFromSpec(fieldType) {
20517
+ const typeSpec = primitiveTypeSpecFromFieldSpec(fieldType);
20518
+ if (!typeSpec)
20519
+ return null;
20520
+ const base = typeSpec.endsWith("?") ? typeSpec.slice(0, -1) : typeSpec;
20521
+ return BASE_PRIMITIVE_TYPE_SET.has(base) ? base : null;
20522
+ }
20523
+ function fieldDescriptionFromSpec(fieldType) {
20524
+ let unwrapped = fieldType;
20525
+ if (Array.isArray(fieldType) && fieldType.length === 1) {
20526
+ unwrapped = fieldType[0];
20365
20527
  }
20366
- if (op.members) {
20367
- fields.push(...op.members);
20528
+ if (isTypeSpecObject(unwrapped)) {
20529
+ if (typeof unwrapped.description === "string")
20530
+ return unwrapped.description;
20531
+ if ((unwrapped.type === "array" || unwrapped.type === "array?") && "items" in unwrapped) {
20532
+ return fieldDescriptionFromSpec(unwrapped.items);
20533
+ }
20534
+ return;
20368
20535
  }
20369
- return fields;
20536
+ return;
20370
20537
  }
20371
- function rejectCommitTokenSyntax(operations, errors) {
20372
- for (let i = 0;i < operations.length; i++) {
20373
- const op = operations[i];
20374
- if (!op)
20375
- continue;
20376
- for (const field of tokenStringFields(op)) {
20377
- if (field && hasAnyTokens(field)) {
20378
- errors.push({
20379
- code: "COMMIT_TOKEN_SYNTAX_REMOVED",
20380
- operationIndex: i,
20381
- message: COMMIT_TOKEN_SYNTAX_REMOVED_MESSAGE
20382
- });
20383
- break;
20384
- }
20538
+ function displayFieldType(fieldType) {
20539
+ if (typeof fieldType === "string")
20540
+ return fieldType;
20541
+ if (Array.isArray(fieldType)) {
20542
+ if (fieldType.length === 1) {
20543
+ return `${displayFieldType(fieldType[0])}[]`;
20544
+ }
20545
+ return JSON.stringify(fieldType) ?? "unknown";
20546
+ }
20547
+ if (isPlainObject(fieldType)) {
20548
+ if (isTypeSpecObject(fieldType)) {
20549
+ return formatTypeSpecDisplay(fieldType);
20550
+ }
20551
+ if ("type" in fieldType) {
20552
+ return JSON.stringify(fieldType);
20385
20553
  }
20386
20554
  }
20387
- }
20388
- function illegalOpSequences(operations, errors, checkAddAdd) {
20389
- const opHistory = new Map;
20390
- for (let i = 0;i < operations.length; i++) {
20391
- const op = operations[i];
20392
- if (!op)
20393
- continue;
20394
- const name = getOpName(op);
20395
- if (!name)
20396
- continue;
20397
- if (hasAnyTokens(name))
20398
- continue;
20399
- const kind = inferOperationKind({ ...op, name });
20400
- const qualName = kind === "shape" ? `shape:${name}` : `thing:${name}`;
20401
- const history = opHistory.get(qualName) ?? [];
20402
- history.push({ operation: op.operation, index: i });
20403
- opHistory.set(qualName, history);
20404
- }
20405
- for (const [qualName, history] of opHistory) {
20406
- if (history.length < 2)
20407
- continue;
20408
- for (let i = 1;i < history.length; i++) {
20409
- const prev = history[i - 1];
20410
- const curr = history[i];
20411
- if (!prev || !curr)
20412
- continue;
20413
- const pair = `${prev.operation}+${curr.operation}`;
20414
- if (checkAddAdd && pair === "add+add") {
20415
- errors.push({
20416
- code: "ILLEGAL_OP_SEQUENCE",
20417
- operationIndex: curr.index,
20418
- message: `Cannot add "${qualName}" twice in the same commit`
20419
- });
20420
- }
20421
- if (pair === "revise+add") {
20422
- errors.push({
20423
- code: "ILLEGAL_OP_SEQUENCE",
20424
- operationIndex: curr.index,
20425
- message: `Cannot revise then add "${qualName}" in the same commit`
20426
- });
20427
- }
20428
- }
20429
- }
20430
- }
20431
-
20432
- // ../../packages/rules/src/preflight-operation.ts
20433
- var collectionTypes = ["arc", "bond", "set", "list", "pair"];
20434
- var canonicalCollectionTypes = ["arc", "bond", "set", "list"];
20435
- var collectionOps = ["add", "revise"];
20436
- var COLLECTION_CREATE_REQUIRES_NAME_MESSAGE = "Collection create requires a name. Collections are ordinary named things (ADR 0004).";
20437
- 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":"arc","name":"a-to-b","members":["A","B"]},{"operation":"add","kind":"assertion","about":"Arc/a-to-b","name":"Assertion/example","data":{}}]. For CLI usage, use wh commit submit --file with the two operations.';
20438
- function preflightOpDiagnostics(op, operationIndex) {
20439
- const errors = [];
20440
- errors.push(...builtinShapeGuard(op, operationIndex));
20441
- errors.push(...contentNameGuard(op, operationIndex));
20442
- errors.push(...plusSignGuard(op, operationIndex));
20443
- errors.push(...validateCollectionAbouts(op, operationIndex));
20444
- errors.push(...validateCollectionOps(op, operationIndex));
20445
- return errors;
20446
- }
20447
- function builtinShapeGuard(op, operationIndex) {
20448
- const errors = [];
20449
- const name = op.name;
20450
- const isShapeRename = op.operation === "rename" && (op.kind === "shape" || op.name !== undefined && !splitLocalPath(op.name));
20451
- const reservedSourcePassThrough = isShapeRename && name !== undefined && isReservedCollectionShape(name) && op.newName !== undefined && !isReservedCollectionShape(op.newName) && !isBuiltinShape(op.newName);
20452
- if (name && isRetiredCollectionShape(name) && !reservedSourcePassThrough) {
20453
- errors.push({
20454
- code: "RESERVED_NAME",
20455
- operationIndex,
20456
- message: `Shape "${name}" is a retired collection shape and cannot be written manually`
20457
- });
20458
- }
20459
- if (op.operation === "rename" && (op.kind === "shape" || op.name !== undefined && !splitLocalPath(op.name)) && op.newName && isRetiredCollectionShape(op.newName)) {
20460
- errors.push({
20461
- code: "RESERVED_NAME",
20462
- operationIndex,
20463
- message: `Shape "${op.newName}" is a retired collection shape and cannot be written manually`
20464
- });
20465
- } else {
20466
- const builtinShapeName = name && isBuiltinShape(name) && !reservedSourcePassThrough ? name : isShapeRename && op.newName && isBuiltinShape(op.newName) ? op.newName : undefined;
20467
- if (builtinShapeName && (isShapeRename || op.operation !== "retract" && op.kind === "shape")) {
20468
- const action = op.operation === "add" ? "created" : op.operation === "rename" ? "renamed" : "revised";
20469
- errors.push({
20470
- code: "RESERVED_NAME",
20471
- operationIndex,
20472
- message: `Shape "${builtinShapeName}" is a built-in shape and cannot be ${action} manually`
20473
- });
20474
- }
20475
- }
20476
- if (name) {
20477
- const local = splitLocalPath(name);
20478
- if (local && isRetiredCollectionShape(local.shapePrefix)) {
20479
- errors.push({
20480
- code: "VALIDATION_ERROR",
20481
- operationIndex,
20482
- message: `Cannot ${op.operation} under retired collection shape "${local.shapePrefix}". Triple is read-only and retired for new collection writes.`
20483
- });
20484
- } else if (op.kind === "thing" && local && isBuiltinCollectionShape(local.shapePrefix)) {
20485
- 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.`;
20486
- errors.push({
20487
- code: "VALIDATION_ERROR",
20488
- operationIndex,
20489
- message
20490
- });
20491
- }
20492
- }
20493
- return errors;
20494
- }
20495
- function contentNameGuard(op, operationIndex) {
20496
- if (op.kind !== "thing" || !op.name)
20497
- return [];
20498
- const local = splitLocalPath(op.name);
20499
- if (!local || !isContentShape(local.shapePrefix))
20500
- return [];
20501
- const bareName = local.bareName;
20502
- if (isSynthesizedContentName(bareName)) {
20503
- return [
20504
- {
20505
- code: "READ_ONLY_BUILTIN_CONTENT",
20506
- operationIndex,
20507
- message: `${local.shapePrefix}/${bareName} is synthesized; writes are not allowed`
20508
- }
20509
- ];
20510
- }
20511
- if (!isStoredContentName(bareName)) {
20512
- return [
20513
- {
20514
- code: "UNKNOWN_CONTENT_NAME",
20515
- operationIndex,
20516
- message: `${local.shapePrefix}/${bareName} is not a recognized well-known content name`
20517
- }
20518
- ];
20519
- }
20520
- return [];
20521
- }
20522
- function plusSignGuard(op, operationIndex) {
20523
- const errors = [];
20524
- const name = op.name;
20525
- if (op.newName?.includes("+")) {
20526
- errors.push({
20527
- code: "VALIDATION_ERROR",
20528
- operationIndex,
20529
- 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.`
20530
- });
20531
- return errors;
20532
- }
20533
- if (name?.includes("+")) {
20534
- if (op.kind === "collection" && op.operation === "add") {
20535
- errors.push({
20536
- code: "VALIDATION_ERROR",
20537
- operationIndex,
20538
- 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.`
20539
- });
20540
- return errors;
20541
- }
20542
- if (op.kind === "collection")
20543
- return errors;
20544
- const local = splitLocalPath(name);
20545
- if (local && isReservedCollectionShape(local.shapePrefix))
20546
- return errors;
20547
- errors.push({
20548
- code: "VALIDATION_ERROR",
20549
- operationIndex,
20550
- 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.`
20551
- });
20552
- }
20553
- return errors;
20554
- }
20555
- function validateCollectionAbouts(op, operationIndex) {
20556
- const errors = [];
20557
- if (!op.about || typeof op.about === "string")
20558
- return errors;
20559
- errors.push({
20560
- code: "VALIDATION_ERROR",
20561
- operationIndex,
20562
- message: COLLECTION_ABOUT_REMOVED_MESSAGE
20563
- });
20564
- return errors;
20565
- }
20566
- function validateCollectionOps(op, operationIndex) {
20567
- const errors = [];
20568
- if (op.kind !== "collection")
20569
- return errors;
20570
- if (!collectionOps.includes(op.operation)) {
20571
- return errors;
20572
- }
20573
- if (op.operation === "add" && !op.name) {
20574
- errors.push({
20575
- code: "VALIDATION_ERROR",
20576
- operationIndex,
20577
- message: COLLECTION_CREATE_REQUIRES_NAME_MESSAGE
20578
- });
20579
- }
20580
- if (!op.type || !collectionTypes.includes(op.type)) {
20581
- errors.push({
20582
- code: "VALIDATION_ERROR",
20583
- operationIndex,
20584
- message: `Collection "type" is invalid. Use one of: ${canonicalCollectionTypes.join(", ")}. Got: "${op.type ?? ""}"`
20585
- });
20586
- }
20587
- if (!op.members || !Array.isArray(op.members)) {
20588
- errors.push({
20589
- code: "VALIDATION_ERROR",
20590
- operationIndex,
20591
- message: 'Collection requires a "members" array'
20592
- });
20593
- } else {
20594
- for (let i = 0;i < op.members.length; i++) {
20595
- if (typeof op.members[i] !== "string") {
20596
- errors.push({
20597
- code: "VALIDATION_ERROR",
20598
- operationIndex,
20599
- message: `Collection member at index ${i} must be a string`
20600
- });
20601
- }
20602
- }
20603
- }
20604
- if (op.type && op.members) {
20605
- const arityError = collectionArityError(op.type, op.members);
20606
- if (arityError) {
20607
- errors.push({
20608
- code: "VALIDATION_ERROR",
20609
- operationIndex,
20610
- message: arityError
20611
- });
20612
- }
20613
- }
20614
- return errors;
20615
- }
20616
- function collectionArityError(tag, members) {
20617
- switch (tag) {
20618
- case "arc":
20619
- return members.length !== 2 ? `Arc requires exactly 2 members, got ${members.length}` : null;
20620
- case "bond":
20621
- return members.length !== 2 ? `Bond requires exactly 2 members, got ${members.length}` : null;
20622
- case "pair":
20623
- return members.length !== 2 ? `Pair requires exactly 2 members, got ${members.length}` : null;
20624
- case "set":
20625
- case "list":
20626
- return members.length < 1 ? `${tag === "set" ? "Set" : "List"} requires at least 1 member, got 0` : null;
20627
- }
20628
- }
20629
- // ../../packages/rules/src/preflight.ts
20630
- function preflightOpDiagnostics2(op, operationIndex) {
20631
- return preflightOpDiagnostics(op, operationIndex);
20632
- }
20633
- function preflightCommitDiagnostics2(operations, options) {
20634
- return preflightCommitDiagnostics(operations, options);
20635
- }
20636
- // ../../packages/rules/src/read-limits.ts
20637
- var MAX_GET_MANY_WREFS = 500;
20638
- // ../../packages/rules/src/reserved-orgs.ts
20639
- var RESERVED_RAW_CONTENT_TOP_LEVEL_NAMES = [
20640
- "_app",
20641
- "_static",
20642
- "api",
20643
- "health",
20644
- "healthz",
20645
- "mcp",
20646
- "readyz",
20647
- "robots.txt",
20648
- "sse",
20649
- "trpc",
20650
- "version"
20651
- ];
20652
- var RESERVED_ORG_NAMES = [
20653
- ...RESERVED_RAW_CONTENT_TOP_LEVEL_NAMES,
20654
- "admin",
20655
- "billing",
20656
- "blog",
20657
- "docs",
20658
- "help",
20659
- "login",
20660
- "public",
20661
- "settings",
20662
- "signup",
20663
- "status",
20664
- "support",
20665
- "system",
20666
- "warmhub",
20667
- "www"
20668
- ];
20669
- var RESERVED_ORG_NAME_SET = new Set(RESERVED_ORG_NAMES);
20670
- // ../../packages/rules/src/shape-field-key.ts
20671
- function foldFieldName(name) {
20672
- const stripped = name.endsWith("?") ? name.slice(0, -1) : name;
20673
- return stripped.toLowerCase();
20674
- }
20675
- function foldFieldPath(path) {
20676
- return path.split(".").map((segment) => foldFieldName(segment)).join(".");
20677
- }
20678
- // ../../packages/rules/src/shape-types.ts
20679
- var BASE_PRIMITIVE_TYPES = [
20680
- "number",
20681
- "string",
20682
- "boolean",
20683
- "wref",
20684
- "array"
20685
- ];
20686
- var BASE_PRIMITIVE_TYPE_SET = new Set(BASE_PRIMITIVE_TYPES);
20687
- var VALID_PRIMITIVE_TYPES = new Set([
20688
- "number",
20689
- "string",
20690
- "boolean",
20691
- "wref",
20692
- "array",
20693
- "number?",
20694
- "string?",
20695
- "boolean?",
20696
- "wref?",
20697
- "array?"
20698
- ]);
20699
- function isPlainObject(value) {
20700
- return typeof value === "object" && value !== null && !Array.isArray(value);
20701
- }
20702
- var STRING_CONSTRAINT_KEYS = new Set([
20703
- "minLength",
20704
- "maxLength",
20705
- "pattern",
20706
- "enum"
20707
- ]);
20708
- var NUMBER_CONSTRAINT_KEYS = new Set(["minimum", "maximum", "integer"]);
20709
- var WREF_CONSTRAINT_KEYS = new Set(["shape"]);
20710
- var ARRAY_CONSTRAINT_KEYS = new Set(["items", "minItems", "maxItems"]);
20711
- var COMMON_TYPESPEC_KEYS = new Set(["type", "description"]);
20712
- var VALID_TYPESPEC_KEYS = new Set([
20713
- ...COMMON_TYPESPEC_KEYS,
20714
- ...STRING_CONSTRAINT_KEYS,
20715
- ...NUMBER_CONSTRAINT_KEYS,
20716
- ...WREF_CONSTRAINT_KEYS,
20717
- ...ARRAY_CONSTRAINT_KEYS
20718
- ]);
20719
- var CONSTRAINT_KEYS_BY_TYPE = {
20720
- string: STRING_CONSTRAINT_KEYS,
20721
- number: NUMBER_CONSTRAINT_KEYS,
20722
- wref: WREF_CONSTRAINT_KEYS,
20723
- array: ARRAY_CONSTRAINT_KEYS,
20724
- boolean: new Set
20725
- };
20726
- function isTypeSpecObject(value) {
20727
- if (!isPlainObject(value) || !("type" in value))
20728
- return false;
20729
- if (typeof value.type !== "string" || !VALID_PRIMITIVE_TYPES.has(value.type))
20730
- return false;
20731
- const baseType = value.type.endsWith("?") ? value.type.slice(0, -1) : value.type;
20732
- const allowedConstraints = CONSTRAINT_KEYS_BY_TYPE[baseType] ?? new Set;
20733
- if (!Object.keys(value).every((k) => COMMON_TYPESPEC_KEYS.has(k) || allowedConstraints.has(k)))
20734
- return false;
20735
- if ("minLength" in value && typeof value.minLength !== "number")
20736
- return false;
20737
- if ("maxLength" in value && typeof value.maxLength !== "number")
20738
- return false;
20739
- if ("pattern" in value && typeof value.pattern !== "string")
20740
- return false;
20741
- if ("pattern" in value && typeof value.pattern === "string" && VALID_PRIMITIVE_TYPES.has(value.pattern)) {
20742
- const baseType2 = typeof value.type === "string" && value.type.endsWith("?") ? value.type.slice(0, -1) : value.type;
20743
- if (baseType2 !== "string")
20744
- return false;
20745
- }
20746
- if ("enum" in value && !Array.isArray(value.enum))
20747
- return false;
20748
- if ("minimum" in value && typeof value.minimum !== "number")
20749
- return false;
20750
- if ("maximum" in value && typeof value.maximum !== "number")
20751
- return false;
20752
- if ("integer" in value && typeof value.integer !== "boolean")
20753
- return false;
20754
- if ("shape" in value && typeof value.shape !== "string")
20755
- return false;
20756
- if ("shape" in value && typeof value.shape === "string" && VALID_PRIMITIVE_TYPES.has(value.shape)) {
20757
- const baseType2 = typeof value.type === "string" && value.type.endsWith("?") ? value.type.slice(0, -1) : value.type;
20758
- if (baseType2 !== "wref")
20759
- return false;
20760
- }
20761
- if ("items" in value && typeof value.items === "number")
20762
- return false;
20763
- if ("items" in value && typeof value.items === "boolean")
20764
- return false;
20765
- if ("minItems" in value && typeof value.minItems !== "number")
20766
- return false;
20767
- if ("maxItems" in value && typeof value.maxItems !== "number")
20768
- return false;
20769
- return true;
20770
- }
20771
- function primitiveTypeSpecFromFieldSpec(fieldType) {
20772
- if (typeof fieldType === "string" && VALID_PRIMITIVE_TYPES.has(fieldType)) {
20773
- return fieldType;
20774
- }
20775
- if (isTypeSpecObject(fieldType)) {
20776
- return fieldType.type;
20777
- }
20778
- return null;
20779
- }
20780
- function basePrimitiveTypeFromSpec(fieldType) {
20781
- const typeSpec = primitiveTypeSpecFromFieldSpec(fieldType);
20782
- if (!typeSpec)
20783
- return null;
20784
- const base = typeSpec.endsWith("?") ? typeSpec.slice(0, -1) : typeSpec;
20785
- return BASE_PRIMITIVE_TYPE_SET.has(base) ? base : null;
20786
- }
20787
- function fieldDescriptionFromSpec(fieldType) {
20788
- let unwrapped = fieldType;
20789
- if (Array.isArray(fieldType) && fieldType.length === 1) {
20790
- unwrapped = fieldType[0];
20791
- }
20792
- if (isTypeSpecObject(unwrapped)) {
20793
- if (typeof unwrapped.description === "string")
20794
- return unwrapped.description;
20795
- if ((unwrapped.type === "array" || unwrapped.type === "array?") && "items" in unwrapped) {
20796
- return fieldDescriptionFromSpec(unwrapped.items);
20797
- }
20798
- return;
20799
- }
20800
- return;
20801
- }
20802
- function displayFieldType(fieldType) {
20803
- if (typeof fieldType === "string")
20804
- return fieldType;
20805
- if (Array.isArray(fieldType)) {
20806
- if (fieldType.length === 1) {
20807
- return `${displayFieldType(fieldType[0])}[]`;
20808
- }
20809
- return JSON.stringify(fieldType) ?? "unknown";
20810
- }
20811
- if (isPlainObject(fieldType)) {
20812
- if (isTypeSpecObject(fieldType)) {
20813
- return formatTypeSpecDisplay(fieldType);
20814
- }
20815
- if ("type" in fieldType) {
20816
- return JSON.stringify(fieldType);
20817
- }
20818
- }
20819
- return JSON.stringify(fieldType) ?? "unknown";
20555
+ return JSON.stringify(fieldType) ?? "unknown";
20820
20556
  }
20821
20557
  function formatTypeSpecDisplay(spec) {
20822
20558
  const baseType = spec.type;
@@ -20872,6 +20608,7 @@ function displayFieldEntry(fieldType) {
20872
20608
  return { type, description };
20873
20609
  return type;
20874
20610
  }
20611
+
20875
20612
  // ../../node_modules/.bun/re2js@2.8.3/node_modules/re2js/build/index.js
20876
20613
  /*!
20877
20614
  * re2js
@@ -27195,177 +26932,536 @@ var RE2JS = class RE2JS2 {
27195
26932
  input = MatcherInput.utf8(input);
27196
26933
  return new Matcher(this, input);
27197
26934
  }
27198
- test(input) {
27199
- if (Utils.isByteArray(input))
27200
- return this.re2Input.matchUTF8(input);
27201
- return this.re2Input.match(input);
26935
+ test(input) {
26936
+ if (Utils.isByteArray(input))
26937
+ return this.re2Input.matchUTF8(input);
26938
+ return this.re2Input.match(input);
26939
+ }
26940
+ testExact(input) {
26941
+ const machineInput = Utils.isByteArray(input) ? MachineInput.fromUTF8(input) : MachineInput.fromUTF16(input);
26942
+ return this.re2Input.executeEngine(machineInput, 0, RE2Flags.ANCHOR_BOTH, 0) !== null;
26943
+ }
26944
+ split(input, limit = 0) {
26945
+ const m = this.matcher(input);
26946
+ const result = [];
26947
+ let emptiesSkipped = 0;
26948
+ let last = 0;
26949
+ while (m.find()) {
26950
+ if (last === 0 && m.end() === 0) {
26951
+ last = m.end();
26952
+ continue;
26953
+ }
26954
+ if (limit > 0 && result.length === limit - 1)
26955
+ break;
26956
+ if (last === m.start()) {
26957
+ if (limit === 0) {
26958
+ emptiesSkipped += 1;
26959
+ last = m.end();
26960
+ continue;
26961
+ }
26962
+ } else
26963
+ while (emptiesSkipped > 0) {
26964
+ result.push("");
26965
+ emptiesSkipped -= 1;
26966
+ }
26967
+ result.push(m.substring(last, m.start()));
26968
+ last = m.end();
26969
+ }
26970
+ if (limit === 0 && last !== m.inputLength()) {
26971
+ while (emptiesSkipped > 0) {
26972
+ result.push("");
26973
+ emptiesSkipped -= 1;
26974
+ }
26975
+ result.push(m.substring(last, m.inputLength()));
26976
+ }
26977
+ if (limit !== 0 || result.length === 0)
26978
+ result.push(m.substring(last, m.inputLength()));
26979
+ return result;
26980
+ }
26981
+ *matchAll(input) {
26982
+ const m = this.matcher(input);
26983
+ while (m.find()) {
26984
+ const result = [m.group(0)];
26985
+ for (let i = 1;i <= m.groupCount(); i++) {
26986
+ const groupVal = m.group(i);
26987
+ result.push(groupVal === null ? undefined : groupVal);
26988
+ }
26989
+ result.index = m.start(0);
26990
+ result.input = input;
26991
+ const namedGroups = this.namedGroups();
26992
+ if (Object.keys(namedGroups).length > 0) {
26993
+ const parsedGroups = m.getNamedGroups();
26994
+ for (const key in parsedGroups)
26995
+ if (parsedGroups[key] === null)
26996
+ parsedGroups[key] = undefined;
26997
+ result.groups = parsedGroups;
26998
+ } else
26999
+ result.groups = undefined;
27000
+ yield result;
27001
+ }
27002
+ }
27003
+ toString() {
27004
+ return this.patternInput;
27005
+ }
27006
+ programSize() {
27007
+ return this.re2Input.numberOfInstructions();
27008
+ }
27009
+ groupCount() {
27010
+ return this.re2Input.numberOfCapturingGroups();
27011
+ }
27012
+ namedGroups() {
27013
+ return this.re2Input.namedGroups;
27014
+ }
27015
+ equals(other) {
27016
+ if (this === other)
27017
+ return true;
27018
+ if (other === null || this.constructor !== other.constructor)
27019
+ return false;
27020
+ return this.flagsInput === other.flagsInput && this.patternInput === other.patternInput;
27021
+ }
27022
+ };
27023
+
27024
+ // ../../packages/rules/src/shape-validation-types.ts
27025
+ var MAX_CONTENT_FIELD_BYTES = 64 * 1024;
27026
+ var MAX_INDEXABLE_SCALAR_FIELDS_PER_SHAPE = 256;
27027
+ var MAX_INDEXABLE_FIELD_PATH_BYTES = 256;
27028
+ var UNSUPPORTED_REGEX_SYNTAX_REASON = "uses unsupported regex syntax";
27029
+ var CONTENT_FIELD_LIMIT_ERROR = `WarmHub content fields are limited to ${MAX_CONTENT_FIELD_BYTES} bytes. ` + "WarmHub is not a document store; store large documents in S3, Box, Drive, or another document system and reference them from WarmHub instead.";
27030
+ var textEncoder = new TextEncoder;
27031
+ function utf8ByteLength(value) {
27032
+ return textEncoder.encode(value).byteLength;
27033
+ }
27034
+ function contentFieldLimitError(path, value) {
27035
+ if (value.length * 3 <= MAX_CONTENT_FIELD_BYTES)
27036
+ return null;
27037
+ const byteLength = utf8ByteLength(value);
27038
+ if (byteLength <= MAX_CONTENT_FIELD_BYTES)
27039
+ return null;
27040
+ return `Field "${path}" is ${byteLength} bytes; ${CONTENT_FIELD_LIMIT_ERROR}`;
27041
+ }
27042
+ function assertContentFieldWithinLimit(path, value, errors) {
27043
+ const message = contentFieldLimitError(path, value);
27044
+ if (message)
27045
+ errors.push(message);
27046
+ }
27047
+ function nativeRegexSyntaxError(pattern) {
27048
+ try {
27049
+ new RegExp(pattern);
27050
+ return false;
27051
+ } catch {
27052
+ return true;
27053
+ }
27054
+ }
27055
+ function normalizePatternForPortableEngine(pattern) {
27056
+ let normalized = "";
27057
+ let inCharacterClass = false;
27058
+ for (let i = 0;i < pattern.length; i++) {
27059
+ const char = pattern[i];
27060
+ if (char === "\\") {
27061
+ const next = pattern[i + 1];
27062
+ if (inCharacterClass && next === "b") {
27063
+ normalized += "\\x08";
27064
+ i++;
27065
+ continue;
27066
+ }
27067
+ normalized += char;
27068
+ if (next !== undefined) {
27069
+ normalized += next;
27070
+ i++;
27071
+ }
27072
+ continue;
27073
+ }
27074
+ if (char === "[") {
27075
+ inCharacterClass = true;
27076
+ } else if (char === "]") {
27077
+ inCharacterClass = false;
27078
+ }
27079
+ normalized += char;
27080
+ }
27081
+ return normalized;
27082
+ }
27083
+ function compilePortablePattern(pattern) {
27084
+ try {
27085
+ return RE2JS.compile(normalizePatternForPortableEngine(pattern));
27086
+ } catch {
27087
+ return;
27088
+ }
27089
+ }
27090
+ function unsupportedPortablePatternReason(pattern) {
27091
+ return compilePortablePattern(pattern) ? undefined : UNSUPPORTED_REGEX_SYNTAX_REASON;
27092
+ }
27093
+ function normalizeOptionalTypeSpec(spec) {
27094
+ if (typeof spec === "string" && spec.endsWith("?")) {
27095
+ return { spec: spec.slice(0, -1), optionalByType: true };
27096
+ }
27097
+ if (isTypeSpecObject(spec) && typeof spec.type === "string" && spec.type.endsWith("?")) {
27098
+ return {
27099
+ spec: { ...spec, type: spec.type.slice(0, -1) },
27100
+ optionalByType: true
27101
+ };
27102
+ }
27103
+ return { spec, optionalByType: false };
27104
+ }
27105
+ // ../../packages/rules/src/external-contract.ts
27106
+ var FORBIDDEN_EXTERNAL_FIELDS = new Set([
27107
+ "_id",
27108
+ "_creationTime",
27109
+ "repoId",
27110
+ "orgId",
27111
+ "thingId",
27112
+ "shapeThingId",
27113
+ "aboutThingId",
27114
+ "currentVersionId",
27115
+ "createdInCommitId",
27116
+ "validatedShapeVersionId"
27117
+ ]);
27118
+ // ../../packages/rules/src/name-charset.ts
27119
+ var RESERVED_NAME_SEGMENT_CHARS = ["?", "#", "@", ":", "$"];
27120
+ function escapeForCharClass(char) {
27121
+ return char.replace(/[\\\]^-]/g, "\\$&");
27122
+ }
27123
+ var RESERVED_CLASS_BODY = RESERVED_NAME_SEGMENT_CHARS.map(escapeForCharClass).join("");
27124
+ var NAME_SEGMENT_FORBIDDEN_RE = new RegExp(`[${RESERVED_CLASS_BODY}\\s]`);
27125
+ var PATH_SEGMENT_FORBIDDEN_RE = new RegExp(`[/${RESERVED_CLASS_BODY}\\s]`);
27126
+ // ../../packages/rules/src/permission-scopes.ts
27127
+ var PUBLIC_ORG_PERMISSIONS = new Set([
27128
+ "org:read",
27129
+ "components:read"
27130
+ ]);
27131
+ // ../../packages/rules/src/tokens.ts
27132
+ 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.";
27133
+ var ANY_TOKEN_RE = /[$#]\d+/;
27134
+ function hasAnyTokens(s) {
27135
+ return ANY_TOKEN_RE.test(s);
27136
+ }
27137
+
27138
+ // ../../packages/rules/src/preflight-commit.ts
27139
+ function preflightCommitDiagnostics(operations, options) {
27140
+ const errors = [];
27141
+ rejectCommitTokenSyntax(operations, errors);
27142
+ illegalOpSequences(operations, errors, options?.checkAddAdd ?? true);
27143
+ return errors;
27144
+ }
27145
+ function getOpName(op) {
27146
+ return op.name;
27147
+ }
27148
+ function tokenStringFields(op) {
27149
+ const fields = [getOpName(op), op.newName];
27150
+ if (typeof op.about === "string") {
27151
+ fields.push(op.about);
27202
27152
  }
27203
- testExact(input) {
27204
- const machineInput = Utils.isByteArray(input) ? MachineInput.fromUTF8(input) : MachineInput.fromUTF16(input);
27205
- return this.re2Input.executeEngine(machineInput, 0, RE2Flags.ANCHOR_BOTH, 0) !== null;
27153
+ if (op.members) {
27154
+ fields.push(...op.members);
27206
27155
  }
27207
- split(input, limit = 0) {
27208
- const m = this.matcher(input);
27209
- const result = [];
27210
- let emptiesSkipped = 0;
27211
- let last = 0;
27212
- while (m.find()) {
27213
- if (last === 0 && m.end() === 0) {
27214
- last = m.end();
27215
- continue;
27216
- }
27217
- if (limit > 0 && result.length === limit - 1)
27156
+ return fields;
27157
+ }
27158
+ function rejectCommitTokenSyntax(operations, errors) {
27159
+ for (let i = 0;i < operations.length; i++) {
27160
+ const op = operations[i];
27161
+ if (!op)
27162
+ continue;
27163
+ for (const field of tokenStringFields(op)) {
27164
+ if (field && hasAnyTokens(field)) {
27165
+ errors.push({
27166
+ code: "COMMIT_TOKEN_SYNTAX_REMOVED",
27167
+ operationIndex: i,
27168
+ message: COMMIT_TOKEN_SYNTAX_REMOVED_MESSAGE
27169
+ });
27218
27170
  break;
27219
- if (last === m.start()) {
27220
- if (limit === 0) {
27221
- emptiesSkipped += 1;
27222
- last = m.end();
27223
- continue;
27224
- }
27225
- } else
27226
- while (emptiesSkipped > 0) {
27227
- result.push("");
27228
- emptiesSkipped -= 1;
27229
- }
27230
- result.push(m.substring(last, m.start()));
27231
- last = m.end();
27232
- }
27233
- if (limit === 0 && last !== m.inputLength()) {
27234
- while (emptiesSkipped > 0) {
27235
- result.push("");
27236
- emptiesSkipped -= 1;
27237
27171
  }
27238
- result.push(m.substring(last, m.inputLength()));
27239
27172
  }
27240
- if (limit !== 0 || result.length === 0)
27241
- result.push(m.substring(last, m.inputLength()));
27242
- return result;
27243
27173
  }
27244
- *matchAll(input) {
27245
- const m = this.matcher(input);
27246
- while (m.find()) {
27247
- const result = [m.group(0)];
27248
- for (let i = 1;i <= m.groupCount(); i++) {
27249
- const groupVal = m.group(i);
27250
- result.push(groupVal === null ? undefined : groupVal);
27174
+ }
27175
+ function illegalOpSequences(operations, errors, checkAddAdd) {
27176
+ const opHistory = new Map;
27177
+ for (let i = 0;i < operations.length; i++) {
27178
+ const op = operations[i];
27179
+ if (!op)
27180
+ continue;
27181
+ const name = getOpName(op);
27182
+ if (!name)
27183
+ continue;
27184
+ if (hasAnyTokens(name))
27185
+ continue;
27186
+ const kind = inferOperationKind({ ...op, name });
27187
+ const qualName = kind === "shape" ? `shape:${name}` : `thing:${name}`;
27188
+ const history = opHistory.get(qualName) ?? [];
27189
+ history.push({ operation: op.operation, index: i });
27190
+ opHistory.set(qualName, history);
27191
+ }
27192
+ for (const [qualName, history] of opHistory) {
27193
+ if (history.length < 2)
27194
+ continue;
27195
+ for (let i = 1;i < history.length; i++) {
27196
+ const prev = history[i - 1];
27197
+ const curr = history[i];
27198
+ if (!prev || !curr)
27199
+ continue;
27200
+ const pair = `${prev.operation}+${curr.operation}`;
27201
+ if (checkAddAdd && pair === "add+add") {
27202
+ errors.push({
27203
+ code: "ILLEGAL_OP_SEQUENCE",
27204
+ operationIndex: curr.index,
27205
+ message: `Cannot add "${qualName}" twice in the same commit`
27206
+ });
27207
+ }
27208
+ if (pair === "revise+add") {
27209
+ errors.push({
27210
+ code: "ILLEGAL_OP_SEQUENCE",
27211
+ operationIndex: curr.index,
27212
+ message: `Cannot revise then add "${qualName}" in the same commit`
27213
+ });
27251
27214
  }
27252
- result.index = m.start(0);
27253
- result.input = input;
27254
- const namedGroups = this.namedGroups();
27255
- if (Object.keys(namedGroups).length > 0) {
27256
- const parsedGroups = m.getNamedGroups();
27257
- for (const key in parsedGroups)
27258
- if (parsedGroups[key] === null)
27259
- parsedGroups[key] = undefined;
27260
- result.groups = parsedGroups;
27261
- } else
27262
- result.groups = undefined;
27263
- yield result;
27264
27215
  }
27265
27216
  }
27266
- toString() {
27267
- return this.patternInput;
27217
+ }
27218
+
27219
+ // ../../packages/rules/src/preflight-operation.ts
27220
+ var collectionTypes = ["arc", "bond", "set", "list", "pair"];
27221
+ var canonicalCollectionTypes = ["arc", "bond", "set", "list"];
27222
+ var collectionOps = ["add", "revise"];
27223
+ var COLLECTION_CREATE_REQUIRES_NAME_MESSAGE = "Collection create requires a name. Collections are ordinary named things (ADR 0004).";
27224
+ 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":"arc","name":"a-to-b","members":["A","B"]},{"operation":"add","kind":"assertion","about":"Arc/a-to-b","name":"Assertion/example","data":{}}]. For CLI usage, use wh commit submit --file with the two operations.';
27225
+ function preflightOpDiagnostics(op, operationIndex) {
27226
+ const errors = [];
27227
+ errors.push(...builtinShapeGuard(op, operationIndex));
27228
+ errors.push(...contentNameGuard(op, operationIndex));
27229
+ errors.push(...plusSignGuard(op, operationIndex));
27230
+ errors.push(...validateCollectionAbouts(op, operationIndex));
27231
+ errors.push(...validateCollectionOps(op, operationIndex));
27232
+ return errors;
27233
+ }
27234
+ function builtinShapeGuard(op, operationIndex) {
27235
+ const errors = [];
27236
+ const name = op.name;
27237
+ const isShapeRename = op.operation === "rename" && (op.kind === "shape" || op.name !== undefined && !splitLocalPath(op.name));
27238
+ const reservedSourcePassThrough = isShapeRename && name !== undefined && isRenameableSquattedShape(name) && op.newName !== undefined && !isReservedCollectionShape(op.newName) && !isBuiltinShape(op.newName);
27239
+ if (name && isRetiredCollectionShape(name) && !reservedSourcePassThrough) {
27240
+ errors.push({
27241
+ code: "RESERVED_NAME",
27242
+ operationIndex,
27243
+ message: `Shape "${name}" is a retired collection shape and cannot be written manually`
27244
+ });
27268
27245
  }
27269
- programSize() {
27270
- return this.re2Input.numberOfInstructions();
27246
+ if (op.operation === "rename" && (op.kind === "shape" || op.name !== undefined && !splitLocalPath(op.name)) && op.newName && isRetiredCollectionShape(op.newName)) {
27247
+ errors.push({
27248
+ code: "RESERVED_NAME",
27249
+ operationIndex,
27250
+ message: `Shape "${op.newName}" is a retired collection shape and cannot be written manually`
27251
+ });
27252
+ } else {
27253
+ const builtinShapeName = name && isBuiltinShape(name) && !reservedSourcePassThrough ? name : isShapeRename && op.newName && isBuiltinShape(op.newName) ? op.newName : undefined;
27254
+ if (builtinShapeName && (isShapeRename || op.operation !== "retract" && op.kind === "shape")) {
27255
+ const action = op.operation === "add" ? "created" : op.operation === "rename" ? "renamed" : "revised";
27256
+ errors.push({
27257
+ code: "RESERVED_NAME",
27258
+ operationIndex,
27259
+ message: `Shape "${builtinShapeName}" is a built-in shape and cannot be ${action} manually`
27260
+ });
27261
+ }
27271
27262
  }
27272
- groupCount() {
27273
- return this.re2Input.numberOfCapturingGroups();
27263
+ if (name) {
27264
+ const local = splitLocalPath(name);
27265
+ if (local && isRetiredCollectionShape(local.shapePrefix)) {
27266
+ errors.push({
27267
+ code: "VALIDATION_ERROR",
27268
+ operationIndex,
27269
+ message: `Cannot ${op.operation} under retired collection shape "${local.shapePrefix}". Triple is read-only and retired for new collection writes.`
27270
+ });
27271
+ } else if (op.kind === "thing" && local && isBuiltinCollectionShape(local.shapePrefix)) {
27272
+ 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.`;
27273
+ errors.push({
27274
+ code: "VALIDATION_ERROR",
27275
+ operationIndex,
27276
+ message
27277
+ });
27278
+ }
27274
27279
  }
27275
- namedGroups() {
27276
- return this.re2Input.namedGroups;
27280
+ return errors;
27281
+ }
27282
+ function contentNameGuard(op, operationIndex) {
27283
+ if (op.kind !== "thing" || !op.name)
27284
+ return [];
27285
+ const local = splitLocalPath(op.name);
27286
+ if (!local || !isContentShape(local.shapePrefix))
27287
+ return [];
27288
+ const bareName = local.bareName;
27289
+ if (isSynthesizedContentName(bareName)) {
27290
+ return [
27291
+ {
27292
+ code: "READ_ONLY_BUILTIN_CONTENT",
27293
+ operationIndex,
27294
+ message: `${local.shapePrefix}/${bareName} is synthesized; writes are not allowed`
27295
+ }
27296
+ ];
27277
27297
  }
27278
- equals(other) {
27279
- if (this === other)
27280
- return true;
27281
- if (other === null || this.constructor !== other.constructor)
27282
- return false;
27283
- return this.flagsInput === other.flagsInput && this.patternInput === other.patternInput;
27298
+ if (!isStoredContentName(bareName)) {
27299
+ return [
27300
+ {
27301
+ code: "UNKNOWN_CONTENT_NAME",
27302
+ operationIndex,
27303
+ message: `${local.shapePrefix}/${bareName} is not a recognized well-known content name`
27304
+ }
27305
+ ];
27284
27306
  }
27285
- };
27286
-
27287
- // ../../packages/rules/src/shape-validation-types.ts
27288
- var MAX_CONTENT_FIELD_BYTES = 64 * 1024;
27289
- var MAX_INDEXABLE_SCALAR_FIELDS_PER_SHAPE = 256;
27290
- var MAX_INDEXABLE_FIELD_PATH_BYTES = 256;
27291
- var UNSUPPORTED_REGEX_SYNTAX_REASON = "uses unsupported regex syntax";
27292
- var CONTENT_FIELD_LIMIT_ERROR = `WarmHub content fields are limited to ${MAX_CONTENT_FIELD_BYTES} bytes. ` + "WarmHub is not a document store; store large documents in S3, Box, Drive, or another document system and reference them from WarmHub instead.";
27293
- var textEncoder = new TextEncoder;
27294
- function utf8ByteLength(value) {
27295
- return textEncoder.encode(value).byteLength;
27307
+ return [];
27296
27308
  }
27297
- function contentFieldLimitError(path, value) {
27298
- if (value.length * 3 <= MAX_CONTENT_FIELD_BYTES)
27299
- return null;
27300
- const byteLength = utf8ByteLength(value);
27301
- if (byteLength <= MAX_CONTENT_FIELD_BYTES)
27302
- return null;
27303
- return `Field "${path}" is ${byteLength} bytes; ${CONTENT_FIELD_LIMIT_ERROR}`;
27309
+ function plusSignGuard(op, operationIndex) {
27310
+ const errors = [];
27311
+ const name = op.name;
27312
+ if (op.newName?.includes("+")) {
27313
+ errors.push({
27314
+ code: "VALIDATION_ERROR",
27315
+ operationIndex,
27316
+ 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.`
27317
+ });
27318
+ return errors;
27319
+ }
27320
+ if (name?.includes("+")) {
27321
+ if (op.kind === "collection" && op.operation === "add") {
27322
+ errors.push({
27323
+ code: "VALIDATION_ERROR",
27324
+ operationIndex,
27325
+ 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.`
27326
+ });
27327
+ return errors;
27328
+ }
27329
+ if (op.kind === "collection")
27330
+ return errors;
27331
+ const local = splitLocalPath(name);
27332
+ if (local && isReservedCollectionShape(local.shapePrefix))
27333
+ return errors;
27334
+ errors.push({
27335
+ code: "VALIDATION_ERROR",
27336
+ operationIndex,
27337
+ 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.`
27338
+ });
27339
+ }
27340
+ return errors;
27304
27341
  }
27305
- function assertContentFieldWithinLimit(path, value, errors) {
27306
- const message = contentFieldLimitError(path, value);
27307
- if (message)
27308
- errors.push(message);
27342
+ function validateCollectionAbouts(op, operationIndex) {
27343
+ const errors = [];
27344
+ if (!op.about || typeof op.about === "string")
27345
+ return errors;
27346
+ errors.push({
27347
+ code: "VALIDATION_ERROR",
27348
+ operationIndex,
27349
+ message: COLLECTION_ABOUT_REMOVED_MESSAGE
27350
+ });
27351
+ return errors;
27309
27352
  }
27310
- function nativeRegexSyntaxError(pattern) {
27311
- try {
27312
- new RegExp(pattern);
27313
- return false;
27314
- } catch {
27315
- return true;
27353
+ function validateCollectionOps(op, operationIndex) {
27354
+ const errors = [];
27355
+ if (op.kind !== "collection")
27356
+ return errors;
27357
+ if (!collectionOps.includes(op.operation)) {
27358
+ return errors;
27316
27359
  }
27317
- }
27318
- function normalizePatternForPortableEngine(pattern) {
27319
- let normalized = "";
27320
- let inCharacterClass = false;
27321
- for (let i = 0;i < pattern.length; i++) {
27322
- const char = pattern[i];
27323
- if (char === "\\") {
27324
- const next = pattern[i + 1];
27325
- if (inCharacterClass && next === "b") {
27326
- normalized += "\\x08";
27327
- i++;
27328
- continue;
27329
- }
27330
- normalized += char;
27331
- if (next !== undefined) {
27332
- normalized += next;
27333
- i++;
27360
+ if (op.operation === "add" && !op.name) {
27361
+ errors.push({
27362
+ code: "VALIDATION_ERROR",
27363
+ operationIndex,
27364
+ message: COLLECTION_CREATE_REQUIRES_NAME_MESSAGE
27365
+ });
27366
+ }
27367
+ if (!op.type || !collectionTypes.includes(op.type)) {
27368
+ errors.push({
27369
+ code: "VALIDATION_ERROR",
27370
+ operationIndex,
27371
+ message: `Collection "type" is invalid. Use one of: ${canonicalCollectionTypes.join(", ")}. Got: "${op.type ?? ""}"`
27372
+ });
27373
+ }
27374
+ if (!op.members || !Array.isArray(op.members)) {
27375
+ errors.push({
27376
+ code: "VALIDATION_ERROR",
27377
+ operationIndex,
27378
+ message: 'Collection requires a "members" array'
27379
+ });
27380
+ } else {
27381
+ for (let i = 0;i < op.members.length; i++) {
27382
+ if (typeof op.members[i] !== "string") {
27383
+ errors.push({
27384
+ code: "VALIDATION_ERROR",
27385
+ operationIndex,
27386
+ message: `Collection member at index ${i} must be a string`
27387
+ });
27334
27388
  }
27335
- continue;
27336
27389
  }
27337
- if (char === "[") {
27338
- inCharacterClass = true;
27339
- } else if (char === "]") {
27340
- inCharacterClass = false;
27390
+ }
27391
+ if (op.type && op.members) {
27392
+ const arityError = collectionArityError(op.type, op.members);
27393
+ if (arityError) {
27394
+ errors.push({
27395
+ code: "VALIDATION_ERROR",
27396
+ operationIndex,
27397
+ message: arityError
27398
+ });
27341
27399
  }
27342
- normalized += char;
27343
27400
  }
27344
- return normalized;
27401
+ return errors;
27345
27402
  }
27346
- function compilePortablePattern(pattern) {
27347
- try {
27348
- return RE2JS.compile(normalizePatternForPortableEngine(pattern));
27349
- } catch {
27350
- return;
27403
+ function collectionArityError(tag, members) {
27404
+ switch (tag) {
27405
+ case "arc":
27406
+ return members.length !== 2 ? `Arc requires exactly 2 members, got ${members.length}` : null;
27407
+ case "bond":
27408
+ return members.length !== 2 ? `Bond requires exactly 2 members, got ${members.length}` : null;
27409
+ case "pair":
27410
+ return members.length !== 2 ? `Pair requires exactly 2 members, got ${members.length}` : null;
27411
+ case "set":
27412
+ case "list":
27413
+ return members.length < 1 ? `${tag === "set" ? "Set" : "List"} requires at least 1 member, got 0` : null;
27351
27414
  }
27352
27415
  }
27353
- function unsupportedPortablePatternReason(pattern) {
27354
- return compilePortablePattern(pattern) ? undefined : UNSUPPORTED_REGEX_SYNTAX_REASON;
27416
+ // ../../packages/rules/src/preflight.ts
27417
+ function preflightOpDiagnostics2(op, operationIndex) {
27418
+ return preflightOpDiagnostics(op, operationIndex);
27355
27419
  }
27356
- function normalizeOptionalTypeSpec(spec) {
27357
- if (typeof spec === "string" && spec.endsWith("?")) {
27358
- return { spec: spec.slice(0, -1), optionalByType: true };
27359
- }
27360
- if (isTypeSpecObject(spec) && typeof spec.type === "string" && spec.type.endsWith("?")) {
27361
- return {
27362
- spec: { ...spec, type: spec.type.slice(0, -1) },
27363
- optionalByType: true
27364
- };
27365
- }
27366
- return { spec, optionalByType: false };
27420
+ function preflightCommitDiagnostics2(operations, options) {
27421
+ return preflightCommitDiagnostics(operations, options);
27422
+ }
27423
+ // ../../packages/rules/src/read-limits.ts
27424
+ var MAX_GET_MANY_WREFS = 500;
27425
+ // ../../packages/rules/src/reserved-orgs.ts
27426
+ var RESERVED_RAW_CONTENT_TOP_LEVEL_NAMES = [
27427
+ "_app",
27428
+ "_static",
27429
+ "api",
27430
+ "health",
27431
+ "healthz",
27432
+ "mcp",
27433
+ "readyz",
27434
+ "robots.txt",
27435
+ "sse",
27436
+ "trpc",
27437
+ "version"
27438
+ ];
27439
+ var RESERVED_ORG_NAMES = [
27440
+ ...RESERVED_RAW_CONTENT_TOP_LEVEL_NAMES,
27441
+ "admin",
27442
+ "billing",
27443
+ "blog",
27444
+ "docs",
27445
+ "help",
27446
+ "login",
27447
+ "public",
27448
+ "settings",
27449
+ "signup",
27450
+ "status",
27451
+ "support",
27452
+ "system",
27453
+ "warmhub",
27454
+ "www"
27455
+ ];
27456
+ var RESERVED_ORG_NAME_SET = new Set(RESERVED_ORG_NAMES);
27457
+ // ../../packages/rules/src/shape-field-key.ts
27458
+ function foldFieldName(name) {
27459
+ const stripped = name.endsWith("?") ? name.slice(0, -1) : name;
27460
+ return stripped.toLowerCase();
27461
+ }
27462
+ function foldFieldPath(path) {
27463
+ return path.split(".").map((segment) => foldFieldName(segment)).join(".");
27367
27464
  }
27368
-
27369
27465
  // ../../packages/rules/src/shape-validation-runtime.ts
27370
27466
  function validatePersistedStringFieldLimits(value, typeDef, errors, path) {
27371
27467
  const normalized = normalizeOptionalTypeSpec(typeDef).spec;
@@ -27379,8 +27475,9 @@ function validatePersistedStringFieldLimits(value, typeDef, errors, path) {
27379
27475
  }
27380
27476
  if (Array.isArray(value)) {
27381
27477
  const elementType = arrayElementType(normalized);
27382
- if (elementType === undefined && !isDeclaredArrayType(normalized))
27478
+ if (normalized !== undefined && elementType === undefined && !isDeclaredArrayType(normalized)) {
27383
27479
  return;
27480
+ }
27384
27481
  for (let i = 0;i < value.length; i++) {
27385
27482
  validatePersistedStringFieldLimits(value[i], elementType, errors, `${path ?? "<value>"}[${i}]`);
27386
27483
  }
@@ -27392,7 +27489,9 @@ function validatePersistedStringFieldLimits(value, typeDef, errors, path) {
27392
27489
  if (normalized !== undefined && fields === undefined)
27393
27490
  return;
27394
27491
  for (const [key, nestedValue] of Object.entries(value)) {
27395
- validatePersistedStringFieldLimits(nestedValue, fields?.get(key), errors, path ? joinFieldPath(path, key) : escapeFieldNameForDisplay(key));
27492
+ const keyPath = path ? joinFieldPath(path, key) : escapeFieldNameForDisplay(key);
27493
+ assertContentFieldWithinLimit(keyPath, key, errors);
27494
+ validatePersistedStringFieldLimits(nestedValue, fields?.get(key), errors, keyPath);
27396
27495
  }
27397
27496
  }
27398
27497
  function isDeclaredStringType(typeDef) {
@@ -28436,7 +28535,7 @@ function dedupeDeprecationsByShape(results) {
28436
28535
  // ../../packages/sdk-ts/package.json
28437
28536
  var package_default = {
28438
28537
  name: "@warmhub/sdk-ts",
28439
- version: "0.77.1",
28538
+ version: "0.79.0",
28440
28539
  private: false,
28441
28540
  type: "module",
28442
28541
  description: "The TypeScript SDK for WarmHub — create repos, commit and query data, and compound knowledge with your AI agents.",
@@ -29582,6 +29681,26 @@ class WarmHubClient {
29582
29681
  throw toWarmHubError(error);
29583
29682
  }
29584
29683
  },
29684
+ getLicense: async (orgName, repoName) => {
29685
+ try {
29686
+ return await this.trpc.repo.getLicense.query({
29687
+ orgName,
29688
+ repoName
29689
+ });
29690
+ } catch (error) {
29691
+ throw toWarmHubError(error);
29692
+ }
29693
+ },
29694
+ describe: async (orgName, repoName) => {
29695
+ try {
29696
+ return await this.trpc.repo.describe.query({
29697
+ orgName,
29698
+ repoName
29699
+ });
29700
+ } catch (error) {
29701
+ throw toWarmHubError(error);
29702
+ }
29703
+ },
29585
29704
  setReadme: async (orgName, repoName, content) => {
29586
29705
  try {
29587
29706
  assertContentWithinLimit("Content/Readme.content", content);
@@ -29904,6 +30023,13 @@ class WarmHubClient {
29904
30023
  throw toWarmHubError(error);
29905
30024
  }
29906
30025
  },
30026
+ latestRuns: async (orgName, repoName) => {
30027
+ try {
30028
+ return await this.trpc.action.latestRuns.query({ orgName, repoName });
30029
+ } catch (error) {
30030
+ throw toWarmHubError(error);
30031
+ }
30032
+ },
29907
30033
  runStats: async (orgName, repoName, opts) => {
29908
30034
  try {
29909
30035
  return await this.trpc.action.runStats.query({
@@ -42827,6 +42953,42 @@ function getHttpTimeoutSnapshot() {
42827
42953
  return snapshot;
42828
42954
  }
42829
42955
 
42956
+ // ../../packages/warmhub-cli/src/domains/doctor-repo-license.ts
42957
+ var LICENSE_SUBSTRATE = "warmhub-data/global.reference.licenses";
42958
+ async function checkRepoLicenseDeclaration(ctx, repo, repoInfo) {
42959
+ if (repoInfo.visibility !== "public")
42960
+ return null;
42961
+ const safeRepoRef = escapeTerminalTextForDisplay(repo.ref);
42962
+ try {
42963
+ const license = await ctx.client.repo.getLicense(repo.orgName, repo.repoName);
42964
+ if (license) {
42965
+ const safeSpdxId = escapeTerminalTextForDisplay(license.spdxId);
42966
+ return {
42967
+ key: "repo-license",
42968
+ name: "repo-license",
42969
+ status: "ok",
42970
+ message: `Public repo ${safeRepoRef} declares ${safeSpdxId}`
42971
+ };
42972
+ }
42973
+ return {
42974
+ key: "repo-license",
42975
+ name: "repo-license",
42976
+ status: "warn",
42977
+ message: `Public repo ${safeRepoRef} has no repository license declaration.`,
42978
+ detail: `Choose the correct license, then create the native LicenseSubject/repo thing and LicenseDeclaration/repo assertion. Set spdxIdRaw and, when applicable, licenseWref to a canonical License in ${LICENSE_SUBSTRATE}. No component installation is required.`
42979
+ };
42980
+ } catch (error) {
42981
+ const failure = classifyDoctorLookupError(error);
42982
+ const safeDescription = escapeTerminalTextForDisplay(failure.description);
42983
+ return {
42984
+ key: "repo-license",
42985
+ name: "repo-license",
42986
+ status: "warn",
42987
+ message: `Could not verify repository license declaration for public repo ${safeRepoRef}: ${safeDescription}`
42988
+ };
42989
+ }
42990
+ }
42991
+
42830
42992
  // ../../packages/warmhub-cli/src/domains/doctor-checks.ts
42831
42993
  async function collectChecks(ctx) {
42832
42994
  const harnessPaths = getHarnessPaths();
@@ -42872,14 +43034,18 @@ async function collectChecks(ctx) {
42872
43034
  status: apiUrl ? "ok" : "fail",
42873
43035
  message: apiUrl ? `API URL: ${apiUrl}` : "WARMHUB_API_URL not set and no default available"
42874
43036
  });
42875
- const repo = ctx.config.defaultRepo;
42876
- const repoSource = ctx.config.configSource?.repo;
43037
+ const repoFlag = getRepoRef(ctx);
43038
+ const hasRepoFlag = repoFlag !== undefined;
43039
+ const repo = repoFlag ?? ctx.config.defaultRepo;
43040
+ const repoParts = repo !== undefined ? splitRepoSlug(repo) : null;
43041
+ const repoForDisplay = repo !== undefined ? escapeTerminalTextForDisplay(repo) : undefined;
43042
+ const repoSource = hasRepoFlag ? "flag" : ctx.config.configSource?.repo;
42877
43043
  const repoProvenance = repoSource === "env" ? " (from WARMHUB_REPO)" : repoSource === "wh-file" ? " (from .wh file)" : repoSource === "flag" ? " (from --repo flag)" : "";
42878
43044
  checks.push({
42879
43045
  key: "default-repo",
42880
43046
  name: "default-repo",
42881
- status: repo ? "ok" : "warn",
42882
- message: repo ? `Default repo: ${repo}${repoProvenance}` : "No default repo set (use --repo flag, WARMHUB_REPO, or wh use org/repo)"
43047
+ status: repo !== undefined ? repoParts ? "ok" : "fail" : "warn",
43048
+ message: repo !== undefined ? repoParts ? `${hasRepoFlag ? "Target" : "Default"} repo: ${repoForDisplay}${repoProvenance}` : `Invalid repo format "${repoForDisplay}". Expected "org/repo".` : "No default repo set (use --repo flag, WARMHUB_REPO, or wh use org/repo)"
42883
43049
  });
42884
43050
  const profileFlag = ctx.invocation.flags.profile;
42885
43051
  const profile = (typeof profileFlag === "string" ? profileFlag : undefined) ?? ctx.config.profile ?? ctx.profile ?? "default";
@@ -42987,7 +43153,8 @@ async function collectChecks(ctx) {
42987
43153
  });
42988
43154
  }
42989
43155
  }
42990
- if (repo?.includes("/")) {
43156
+ if (repo !== undefined && repoParts) {
43157
+ const safeRepoRef = escapeTerminalTextForDisplay(repo);
42991
43158
  if (!backendOk) {
42992
43159
  checks.push({
42993
43160
  key: "repo",
@@ -42996,22 +43163,25 @@ async function collectChecks(ctx) {
42996
43163
  message: "Skipped (backend unreachable)"
42997
43164
  });
42998
43165
  } else {
42999
- const [orgName, repoName] = repo.split("/", 2);
43166
+ const { org: orgName, repo: repoName } = repoParts;
43000
43167
  try {
43001
- await ctx.client.repo.get(orgName, repoName);
43168
+ const repoInfo = await ctx.client.repo.get(orgName, repoName);
43002
43169
  checks.push({
43003
43170
  key: "repo",
43004
43171
  name: "repo",
43005
43172
  status: "ok",
43006
- message: `Repo ${repo} exists`
43173
+ message: `Repo ${safeRepoRef} exists`
43007
43174
  });
43175
+ const licenseCheck = await checkRepoLicenseDeclaration(ctx, { ref: repo, orgName, repoName }, repoInfo);
43176
+ if (licenseCheck)
43177
+ checks.push(licenseCheck);
43008
43178
  } catch (e) {
43009
43179
  const failure = classifyDoctorLookupError(e);
43010
43180
  checks.push({
43011
43181
  key: "repo",
43012
43182
  name: "repo",
43013
43183
  status: "fail",
43014
- message: failure.classification === "not-found" ? `Repo ${repo} not found: ${failure.description}` : `Repo ${repo} lookup failed: ${failure.description}`
43184
+ message: failure.classification === "not-found" ? `Repo ${safeRepoRef} not found: ${failure.description}` : `Repo ${safeRepoRef} lookup failed: ${failure.description}`
43015
43185
  });
43016
43186
  }
43017
43187
  }
@@ -44720,8 +44890,9 @@ var handleDescribe = async (ctx, { args, flags }) => {
44720
44890
  const { org, repo } = parseOrgRepo(repoRef, ctx.config);
44721
44891
  const c = ctx.colors;
44722
44892
  const showIndexedFields = flags["indexed-fields"] === true;
44723
- const [repoInfo, shapesPage, stats, indexedFields] = await Promise.all([
44893
+ const [repoInfo, license, shapesPage, stats, indexedFields] = await Promise.all([
44724
44894
  ctx.client.repo.get(org, repo),
44895
+ ctx.client.repo.getLicense(org, repo),
44725
44896
  ctx.client.shape.list(org, repo),
44726
44897
  ctx.client.repo.getStats(org, repo),
44727
44898
  showIndexedFields ? ctx.client.repo.index.describe(org, repo) : null
@@ -44744,6 +44915,7 @@ var handleDescribe = async (ctx, { args, flags }) => {
44744
44915
  org,
44745
44916
  repo,
44746
44917
  description: repoInfo.description ?? null,
44918
+ license,
44747
44919
  counts: {
44748
44920
  byKind: stats.byKind,
44749
44921
  byShape
@@ -44767,6 +44939,7 @@ var handleDescribe = async (ctx, { args, flags }) => {
44767
44939
  if (repoInfo.description) {
44768
44940
  ctx.out(` ${escapeTerminalTextForDisplay(repoInfo.description)}`);
44769
44941
  }
44942
+ ctx.out(` License: ${license ? escapeTerminalTextForDisplay(license.spdxExpression ?? license.spdxId) : "not declared"}`);
44770
44943
  ctx.out("");
44771
44944
  ctx.out(`${c.bold}Counts${c.reset} ${stats.byKind.shape} shapes, ${stats.byKind.thing} things, ${stats.byKind.assertion} assertions (${stats.total} total)`);
44772
44945
  const shapeCountEntries = Object.entries(byShape);
@@ -48924,7 +49097,7 @@ function resolveLogLevel(flagLevel, env) {
48924
49097
  // package.json
48925
49098
  var package_default3 = {
48926
49099
  name: "@warmhub/cli",
48927
- version: "0.79.1",
49100
+ version: "0.81.0",
48928
49101
  private: false,
48929
49102
  type: "module",
48930
49103
  description: "The wh CLI for WarmHub — create repos, commit and query data, and compound knowledge with your AI agents.",
@@ -49541,5 +49714,5 @@ process.exitCode = interceptedExitCode === undefined ? await runPreparedCli(laun
49541
49714
  version: package_default3.version
49542
49715
  }) : interceptedExitCode;
49543
49716
 
49544
- //# debugId=4AEF348829257D9564756E2164756E21
49545
- //# warmhub-cli-build-info {"cliVersion":"0.79.1","sdkVersion":"0.77.1"}
49717
+ //# debugId=2DA8F489DEFC62BA64756E2164756E21
49718
+ //# warmhub-cli-build-info {"cliVersion":"0.81.0","sdkVersion":"0.79.0"}