@subcortex-ai/sdk 0.2.0 → 0.3.1

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/index.js CHANGED
@@ -1060,6 +1060,242 @@ function enc2(s) {
1060
1060
  return encodeURIComponent(s);
1061
1061
  }
1062
1062
 
1063
+ // src/types/rules.ts
1064
+ var RulePredicates = {
1065
+ BANNED_PATTERN: "rule:banned_pattern",
1066
+ REQUIRED_PATTERN: "rule:required_pattern",
1067
+ FILE_CONSTRAINT: "rule:file_constraint",
1068
+ REQUIRES_PROPAGATION: "rule:requires_propagation"
1069
+ };
1070
+
1071
+ // src/rules.ts
1072
+ var RULE_PREDICATE_PREFIX = "rule:";
1073
+ var TYPE_TO_PREDICATE = {
1074
+ banned_pattern: RulePredicates.BANNED_PATTERN,
1075
+ required_pattern: RulePredicates.REQUIRED_PATTERN,
1076
+ file_constraint: RulePredicates.FILE_CONSTRAINT,
1077
+ requires_propagation: RulePredicates.REQUIRES_PROPAGATION
1078
+ };
1079
+ function defaultSeverity(confidence) {
1080
+ if (confidence >= 1) return "block";
1081
+ if (confidence >= 0.7) return "warn";
1082
+ return "info";
1083
+ }
1084
+ var RulesNamespace = class {
1085
+ http;
1086
+ tenantId;
1087
+ constructor(http, tenantId) {
1088
+ this.http = http;
1089
+ this.tenantId = tenantId;
1090
+ }
1091
+ /**
1092
+ * Create a new rule.
1093
+ *
1094
+ * Stores an assertion with a `rule:*` predicate and a typed value.
1095
+ * Defaults to confidence 1.0 (enforcement) if not specified.
1096
+ *
1097
+ * @example
1098
+ * ```typescript
1099
+ * await subcortex.rules.create({
1100
+ * subject: 'project:my-project',
1101
+ * type: 'banned_pattern',
1102
+ * pattern: 'as any',
1103
+ * description: 'No any casts — use proper types',
1104
+ * })
1105
+ * ```
1106
+ */
1107
+ async create(input) {
1108
+ const confidence = input.confidence ?? 1;
1109
+ const severity = input.severity ?? defaultSeverity(confidence);
1110
+ const ruleValue = {
1111
+ description: input.description,
1112
+ pattern: input.pattern,
1113
+ fileScope: input.fileScope,
1114
+ propagatesTo: input.propagatesTo
1115
+ };
1116
+ const assertion = await this.http.post(
1117
+ `/api/v1/assertions`,
1118
+ {
1119
+ subject: input.subject,
1120
+ predicate: TYPE_TO_PREDICATE[input.type],
1121
+ value: { ...ruleValue, severity },
1122
+ confidence,
1123
+ tenant_id: input.tenantId ?? this.tenantId
1124
+ },
1125
+ input.tenantId ?? this.tenantId
1126
+ );
1127
+ return parseRule(assertion);
1128
+ }
1129
+ /**
1130
+ * Get a rule by its assertion ID.
1131
+ */
1132
+ async get(ruleId, options) {
1133
+ const tenant = options?.tenantId ?? this.tenantId;
1134
+ const assertion = await this.http.get(
1135
+ `/api/v1/assertions/${enc3(tenant)}/${enc3(ruleId)}`
1136
+ );
1137
+ return parseRule(assertion);
1138
+ }
1139
+ /**
1140
+ * List all rules for this project, optionally filtered by type or severity.
1141
+ */
1142
+ async list(options) {
1143
+ const tenant = options?.tenantId ?? this.tenantId;
1144
+ const assertions = await this.http.get(
1145
+ `/api/v1/assertions/list/${enc3(tenant)}`
1146
+ );
1147
+ return assertions.filter((a) => isRuleAssertion(a)).filter((a) => options?.includeSuperseded || !a.isSuperseded).map(parseRule).filter((r) => !options?.type || r.type === options.type).filter((r) => !options?.severity || r.severity === options.severity);
1148
+ }
1149
+ /**
1150
+ * Get all rules whose fileScope matches the given file path.
1151
+ *
1152
+ * This is the primary query for the PreToolUse hook — "what rules apply
1153
+ * to the file I'm about to modify?"
1154
+ *
1155
+ * @example
1156
+ * ```typescript
1157
+ * const rules = await subcortex.rules.forFile('app/api/users/route.ts')
1158
+ * // Returns banned_pattern and required_pattern rules whose fileScope
1159
+ * // matches the path, plus any project-wide rules without a fileScope.
1160
+ * ```
1161
+ */
1162
+ async forFile(filePath, options) {
1163
+ const allRules = await this.list(options);
1164
+ return allRules.filter((rule) => {
1165
+ if (!rule.value.fileScope) return true;
1166
+ try {
1167
+ const regex = new RegExp(rule.value.fileScope);
1168
+ return regex.test(filePath);
1169
+ } catch {
1170
+ return false;
1171
+ }
1172
+ });
1173
+ }
1174
+ /**
1175
+ * Get all rules scoped to a specific intent subject.
1176
+ *
1177
+ * @example
1178
+ * ```typescript
1179
+ * const apiRules = await subcortex.rules.forIntent('api')
1180
+ * // Queries subject "intent:api" for all rule assertions
1181
+ * ```
1182
+ */
1183
+ async forIntent(intent, options) {
1184
+ const tenant = options?.tenantId ?? this.tenantId;
1185
+ const subject2 = intent.startsWith("intent:") ? intent : `intent:${intent}`;
1186
+ const assertions = await this.http.get(
1187
+ `/api/v1/assertions/query/${enc3(tenant)}/${enc3(subject2)}`
1188
+ );
1189
+ return assertions.filter((a) => isRuleAssertion(a)).filter((a) => options?.includeSuperseded || !a.isSuperseded).map(parseRule).filter((r) => !options?.type || r.type === options.type).filter((r) => !options?.severity || r.severity === options.severity);
1190
+ }
1191
+ /**
1192
+ * Get all rules scoped to a specific subject (project, file, intent, etc.).
1193
+ */
1194
+ async forSubject(subject2, options) {
1195
+ const tenant = options?.tenantId ?? this.tenantId;
1196
+ const assertions = await this.http.get(
1197
+ `/api/v1/assertions/query/${enc3(tenant)}/${enc3(subject2)}`
1198
+ );
1199
+ return assertions.filter((a) => isRuleAssertion(a)).filter((a) => options?.includeSuperseded || !a.isSuperseded).map(parseRule).filter((r) => !options?.type || r.type === options.type).filter((r) => !options?.severity || r.severity === options.severity);
1200
+ }
1201
+ /**
1202
+ * Update a rule by superseding it.
1203
+ *
1204
+ * The old rule is marked as superseded, a new one is created.
1205
+ * Full assertion history is preserved.
1206
+ */
1207
+ async update(input) {
1208
+ const tenant = input.tenantId ?? this.tenantId;
1209
+ const existing = await this.get(input.ruleId, { tenantId: tenant });
1210
+ const confidence = input.confidence ?? existing.confidence;
1211
+ const severity = input.severity ?? existing.severity;
1212
+ const ruleValue = {
1213
+ description: input.description ?? existing.value.description,
1214
+ pattern: input.pattern ?? existing.value.pattern,
1215
+ fileScope: input.fileScope ?? existing.value.fileScope,
1216
+ propagatesTo: input.propagatesTo ?? existing.value.propagatesTo
1217
+ };
1218
+ const assertion = await this.http.post(
1219
+ `/api/v1/assertions/supersede`,
1220
+ {
1221
+ original_assertion_id: input.ruleId,
1222
+ subject: existing.subject,
1223
+ predicate: existing.predicate,
1224
+ value: { ...ruleValue, severity },
1225
+ confidence,
1226
+ tenant_id: tenant
1227
+ },
1228
+ tenant
1229
+ );
1230
+ return parseRule(assertion);
1231
+ }
1232
+ /**
1233
+ * Retract (deactivate) a rule.
1234
+ *
1235
+ * The assertion's temporal bounds are closed. The rule stops matching
1236
+ * in future queries but its history is preserved.
1237
+ */
1238
+ async retract(ruleId, options) {
1239
+ const tenant = options?.tenantId ?? this.tenantId;
1240
+ await this.http.post(
1241
+ `/api/v1/assertions/retract/${enc3(tenant)}/${enc3(ruleId)}`,
1242
+ {},
1243
+ tenant
1244
+ );
1245
+ }
1246
+ };
1247
+ function isRuleAssertion(assertion) {
1248
+ return assertion.predicate?.startsWith(RULE_PREDICATE_PREFIX) ?? false;
1249
+ }
1250
+ function parseRule(assertion) {
1251
+ const predicate = assertion.predicate;
1252
+ const type = predicate.replace(RULE_PREDICATE_PREFIX, "");
1253
+ let ruleValue;
1254
+ let severity;
1255
+ if (typeof assertion.value === "object" && assertion.value !== null) {
1256
+ const val = assertion.value;
1257
+ ruleValue = {
1258
+ description: String(val.description ?? ""),
1259
+ pattern: val.pattern != null ? String(val.pattern) : void 0,
1260
+ fileScope: val.fileScope != null ? String(val.fileScope) : void 0,
1261
+ propagatesTo: Array.isArray(val.propagatesTo) ? val.propagatesTo.map(String) : void 0
1262
+ };
1263
+ severity = val.severity ?? defaultSeverity(assertion.confidence);
1264
+ } else if (typeof assertion.value === "string") {
1265
+ try {
1266
+ const parsed = JSON.parse(assertion.value);
1267
+ ruleValue = {
1268
+ description: String(parsed.description ?? ""),
1269
+ pattern: parsed.pattern != null ? String(parsed.pattern) : void 0,
1270
+ fileScope: parsed.filePattern != null ? String(parsed.filePattern) : void 0,
1271
+ propagatesTo: Array.isArray(parsed.propagatesTo) ? parsed.propagatesTo.map(String) : void 0
1272
+ };
1273
+ severity = parsed.severity ?? defaultSeverity(assertion.confidence);
1274
+ } catch {
1275
+ ruleValue = { description: String(assertion.value) };
1276
+ severity = defaultSeverity(assertion.confidence);
1277
+ }
1278
+ } else {
1279
+ ruleValue = { description: "" };
1280
+ severity = defaultSeverity(assertion.confidence);
1281
+ }
1282
+ return {
1283
+ id: assertion.id,
1284
+ tenantId: assertion.tenantId,
1285
+ subject: assertion.subject,
1286
+ type,
1287
+ predicate,
1288
+ value: ruleValue,
1289
+ severity,
1290
+ confidence: assertion.confidence,
1291
+ validFrom: assertion.validFrom,
1292
+ isSuperseded: assertion.isSuperseded
1293
+ };
1294
+ }
1295
+ function enc3(s) {
1296
+ return encodeURIComponent(s);
1297
+ }
1298
+
1063
1299
  // src/client.ts
1064
1300
  var AssertionsNamespace = class {
1065
1301
  constructor(http, tenantId) {
@@ -1081,21 +1317,21 @@ var AssertionsNamespace = class {
1081
1317
  async get(assertionId, options) {
1082
1318
  const tenantId = options?.tenantId || this.tenantId;
1083
1319
  return this.http.get(
1084
- `/api/v1/assertions/${enc3(tenantId)}/${enc3(assertionId)}`
1320
+ `/api/v1/assertions/${enc4(tenantId)}/${enc4(assertionId)}`
1085
1321
  );
1086
1322
  }
1087
1323
  /** Query assertions by subject. */
1088
1324
  async query(subject2, options) {
1089
1325
  const tenantId = options?.tenantId || this.tenantId;
1090
1326
  return this.http.get(
1091
- `/api/v1/assertions/query/${enc3(tenantId)}/${enc3(subject2)}`
1327
+ `/api/v1/assertions/query/${enc4(tenantId)}/${enc4(subject2)}`
1092
1328
  );
1093
1329
  }
1094
1330
  /** List all active assertions for the tenant. */
1095
1331
  async list(options) {
1096
1332
  const tenantId = options?.tenantId || this.tenantId;
1097
1333
  return this.http.get(
1098
- `/api/v1/assertions/list/${enc3(tenantId)}`
1334
+ `/api/v1/assertions/list/${enc4(tenantId)}`
1099
1335
  );
1100
1336
  }
1101
1337
  /** Supersede an existing assertion with updated values. */
@@ -1114,7 +1350,7 @@ var AssertionsNamespace = class {
1114
1350
  async retract(assertionId, options) {
1115
1351
  const tenantId = options?.tenantId || this.tenantId;
1116
1352
  return this.http.post(
1117
- `/api/v1/assertions/retract/${enc3(tenantId)}/${enc3(assertionId)}`,
1353
+ `/api/v1/assertions/retract/${enc4(tenantId)}/${enc4(assertionId)}`,
1118
1354
  {}
1119
1355
  );
1120
1356
  }
@@ -1141,14 +1377,14 @@ var RelationshipsNamespace = class {
1141
1377
  async query(subject2, options) {
1142
1378
  const tenantId = options?.tenantId || this.tenantId;
1143
1379
  return this.http.get(
1144
- `/api/v1/relationships/${enc3(tenantId)}/${enc3(subject2)}`
1380
+ `/api/v1/relationships/${enc4(tenantId)}/${enc4(subject2)}`
1145
1381
  );
1146
1382
  }
1147
1383
  /** List all relationships for the tenant. */
1148
1384
  async list(options) {
1149
1385
  const tenantId = options?.tenantId || this.tenantId;
1150
1386
  return this.http.get(
1151
- `/api/v1/relationships/list/${enc3(tenantId)}`
1387
+ `/api/v1/relationships/list/${enc4(tenantId)}`
1152
1388
  );
1153
1389
  }
1154
1390
  };
@@ -1175,14 +1411,14 @@ var AgentsNamespace = class {
1175
1411
  async get(agentId, options) {
1176
1412
  const tenantId = options?.tenantId || this.tenantId;
1177
1413
  return this.http.get(
1178
- `/api/v1/agents/${enc3(tenantId)}/${enc3(agentId)}`
1414
+ `/api/v1/agents/${enc4(tenantId)}/${enc4(agentId)}`
1179
1415
  );
1180
1416
  }
1181
1417
  /** Update an agent. */
1182
1418
  async update(agentId, input, options) {
1183
1419
  const tenantId = options?.tenantId || this.tenantId;
1184
1420
  return this.http.put(
1185
- `/api/v1/agents/${enc3(tenantId)}/${enc3(agentId)}`,
1421
+ `/api/v1/agents/${enc4(tenantId)}/${enc4(agentId)}`,
1186
1422
  {
1187
1423
  tenant_id: tenantId,
1188
1424
  name: input.name,
@@ -1199,20 +1435,20 @@ var AgentsNamespace = class {
1199
1435
  /** Delete an agent. */
1200
1436
  async delete(agentId, options) {
1201
1437
  const tenantId = options?.tenantId || this.tenantId;
1202
- await this.http.delete(`/api/v1/agents/${enc3(tenantId)}/${enc3(agentId)}`);
1438
+ await this.http.delete(`/api/v1/agents/${enc4(tenantId)}/${enc4(agentId)}`);
1203
1439
  }
1204
1440
  /** List all agents for the tenant. */
1205
1441
  async list(options) {
1206
1442
  const tenantId = options?.tenantId || this.tenantId;
1207
1443
  return this.http.get(
1208
- `/api/v1/agents/list/${enc3(tenantId)}`
1444
+ `/api/v1/agents/list/${enc4(tenantId)}`
1209
1445
  );
1210
1446
  }
1211
1447
  /** Get composed system instructions for an agent. */
1212
1448
  async getInstructions(agentId, options) {
1213
1449
  const tenantId = options?.tenantId || this.tenantId;
1214
1450
  return this.http.get(
1215
- `/api/v1/agents/${enc3(tenantId)}/${enc3(agentId)}/instructions`
1451
+ `/api/v1/agents/${enc4(tenantId)}/${enc4(agentId)}/instructions`
1216
1452
  );
1217
1453
  }
1218
1454
  };
@@ -1262,14 +1498,14 @@ var MemoryNamespace = class {
1262
1498
  async recall(subject2, options) {
1263
1499
  const tenantId = options?.tenantId || this.tenantId;
1264
1500
  return this.http.get(
1265
- `/api/v1/assertions/query/${enc3(tenantId)}/${enc3(subject2)}`
1501
+ `/api/v1/assertions/query/${enc4(tenantId)}/${enc4(subject2)}`
1266
1502
  );
1267
1503
  }
1268
1504
  /** Forget a specific memory (retract the assertion). */
1269
1505
  async forget(assertionId, options) {
1270
1506
  const tenantId = options?.tenantId || this.tenantId;
1271
1507
  return this.http.post(
1272
- `/api/v1/assertions/retract/${enc3(tenantId)}/${enc3(assertionId)}`,
1508
+ `/api/v1/assertions/retract/${enc4(tenantId)}/${enc4(assertionId)}`,
1273
1509
  {}
1274
1510
  );
1275
1511
  }
@@ -1301,7 +1537,7 @@ var IntakeNamespace = class {
1301
1537
  }
1302
1538
  /** Get pending intake results for an agent. */
1303
1539
  async pending(agentId, options) {
1304
- let path = `/api/v1/intake/pending/${enc3(agentId)}`;
1540
+ let path = `/api/v1/intake/pending/${enc4(agentId)}`;
1305
1541
  const params = [];
1306
1542
  if (options?.status) params.push(`status=${options.status.join(",")}`);
1307
1543
  if (options?.limit) params.push(`limit=${options.limit}`);
@@ -1310,18 +1546,18 @@ var IntakeNamespace = class {
1310
1546
  }
1311
1547
  /** Acknowledge an intake result (mark as consumed). */
1312
1548
  async acknowledge(itemId) {
1313
- await this.http.post(`/api/v1/intake/acknowledge/${enc3(itemId)}`, {});
1549
+ await this.http.post(`/api/v1/intake/acknowledge/${enc4(itemId)}`, {});
1314
1550
  }
1315
1551
  /** Acknowledge all pending items for an agent. */
1316
1552
  async acknowledgeAll(agentId) {
1317
1553
  return this.http.post(
1318
- `/api/v1/intake/acknowledge-all/${enc3(agentId)}`,
1554
+ `/api/v1/intake/acknowledge-all/${enc4(agentId)}`,
1319
1555
  {}
1320
1556
  );
1321
1557
  }
1322
1558
  /** Get intake processing stats for an agent. */
1323
1559
  async stats(agentId) {
1324
- return this.http.get(`/api/v1/intake/stats/${enc3(agentId)}`);
1560
+ return this.http.get(`/api/v1/intake/stats/${enc4(agentId)}`);
1325
1561
  }
1326
1562
  };
1327
1563
  var ExperiencesNamespace = class {
@@ -1337,14 +1573,14 @@ var ExperiencesNamespace = class {
1337
1573
  if (input?.limit) params.set("limit", String(input.limit));
1338
1574
  const qs = params.toString();
1339
1575
  return this.http.get(
1340
- `/api/v1/experiences/${enc3(tenantId)}${qs ? `?${qs}` : ""}`
1576
+ `/api/v1/experiences/${enc4(tenantId)}${qs ? `?${qs}` : ""}`
1341
1577
  );
1342
1578
  }
1343
1579
  /** Get a single experience by ID. */
1344
1580
  async get(experienceId, options) {
1345
1581
  const tenantId = options?.tenantId || this.tenantId;
1346
1582
  return this.http.get(
1347
- `/api/v1/experiences/${enc3(tenantId)}/${enc3(experienceId)}`
1583
+ `/api/v1/experiences/${enc4(tenantId)}/${enc4(experienceId)}`
1348
1584
  );
1349
1585
  }
1350
1586
  };
@@ -1359,7 +1595,7 @@ var RecallNamespace = class {
1359
1595
  const params = new URLSearchParams({ q: input.query });
1360
1596
  if (input.limit) params.set("limit", String(input.limit));
1361
1597
  return this.http.get(
1362
- `/api/v1/recall/${enc3(tenantId)}?${params.toString()}`
1598
+ `/api/v1/recall/${enc4(tenantId)}?${params.toString()}`
1363
1599
  );
1364
1600
  }
1365
1601
  };
@@ -1372,7 +1608,7 @@ var GraphNamespace = class {
1372
1608
  async findPaths(input) {
1373
1609
  const tenantId = input.tenantId || this.tenantId;
1374
1610
  return this.http.post(
1375
- `/api/v1/graph/${enc3(tenantId)}/paths`,
1611
+ `/api/v1/graph/${enc4(tenantId)}/paths`,
1376
1612
  {
1377
1613
  from: input.from,
1378
1614
  to: input.to,
@@ -1386,7 +1622,7 @@ var GraphNamespace = class {
1386
1622
  async traverse(input) {
1387
1623
  const tenantId = input.tenantId || this.tenantId;
1388
1624
  return this.http.post(
1389
- `/api/v1/graph/${enc3(tenantId)}/traverse`,
1625
+ `/api/v1/graph/${enc4(tenantId)}/traverse`,
1390
1626
  {
1391
1627
  start_subject: input.startSubject,
1392
1628
  max_depth: input.maxDepth,
@@ -1407,7 +1643,7 @@ var TemporalNamespace = class {
1407
1643
  const tenantId = options?.tenantId || this.tenantId;
1408
1644
  const pointStr = point instanceof Date ? point.toISOString() : point;
1409
1645
  return this.http.get(
1410
- `/api/v1/temporal/${enc3(tenantId)}/${enc3(subject2)}/at?point=${enc3(pointStr)}`
1646
+ `/api/v1/temporal/${enc4(tenantId)}/${enc4(subject2)}/at?point=${enc4(pointStr)}`
1411
1647
  );
1412
1648
  }
1413
1649
  /** Get assertions within a date range. */
@@ -1416,7 +1652,7 @@ var TemporalNamespace = class {
1416
1652
  const startStr = start instanceof Date ? start.toISOString() : start;
1417
1653
  const endStr = end instanceof Date ? end.toISOString() : end;
1418
1654
  return this.http.get(
1419
- `/api/v1/temporal/${enc3(tenantId)}/${enc3(subject2)}/range?start=${enc3(startStr)}&end=${enc3(endStr)}`
1655
+ `/api/v1/temporal/${enc4(tenantId)}/${enc4(subject2)}/range?start=${enc4(startStr)}&end=${enc4(endStr)}`
1420
1656
  );
1421
1657
  }
1422
1658
  };
@@ -1429,7 +1665,7 @@ var SearchNamespace = class {
1429
1665
  async semantic(input) {
1430
1666
  const tenantId = input.tenantId || this.tenantId;
1431
1667
  return this.http.post(
1432
- `/api/v1/search/${enc3(tenantId)}/semantic`,
1668
+ `/api/v1/search/${enc4(tenantId)}/semantic`,
1433
1669
  {
1434
1670
  embedding: input.embedding,
1435
1671
  top_k: input.topK
@@ -1519,10 +1755,10 @@ var EntitiesNamespace = class {
1519
1755
  const tenantId = options?.tenantId || this.tenantId;
1520
1756
  const subject2 = `entity:${entityName.toLowerCase().replace(/\s+/g, "-")}`;
1521
1757
  const assertions = await this.http.get(
1522
- `/api/v1/assertions/query/${enc3(tenantId)}/${enc3(subject2)}`
1758
+ `/api/v1/assertions/query/${enc4(tenantId)}/${enc4(subject2)}`
1523
1759
  );
1524
1760
  const relationships = await this.http.get(
1525
- `/api/v1/relationships/query/${enc3(tenantId)}/${enc3(subject2)}`
1761
+ `/api/v1/relationships/query/${enc4(tenantId)}/${enc4(subject2)}`
1526
1762
  );
1527
1763
  const typeAssertion = assertions.find((a) => a.predicate === "type" && !a.isSuperseded);
1528
1764
  const descAssertion = assertions.find((a) => a.predicate === "description" && !a.isSuperseded);
@@ -1530,7 +1766,7 @@ var EntitiesNamespace = class {
1530
1766
  const properties = await Promise.all(
1531
1767
  propertyRels.map(async (rel) => {
1532
1768
  const propAssertions = await this.http.get(
1533
- `/api/v1/assertions/query/${enc3(tenantId)}/${enc3(rel.toSubject)}`
1769
+ `/api/v1/assertions/query/${enc4(tenantId)}/${enc4(rel.toSubject)}`
1534
1770
  );
1535
1771
  const fieldType = propAssertions.find((a) => a.predicate === "field_type" && !a.isSuperseded);
1536
1772
  const required = propAssertions.find((a) => a.predicate === "required" && !a.isSuperseded);
@@ -1560,7 +1796,7 @@ var EntitiesNamespace = class {
1560
1796
  async list(options) {
1561
1797
  const tenantId = options?.tenantId || this.tenantId;
1562
1798
  const all = await this.http.get(
1563
- `/api/v1/assertions/list/${enc3(tenantId)}`
1799
+ `/api/v1/assertions/list/${enc4(tenantId)}`
1564
1800
  );
1565
1801
  return all.filter((a) => a.subject.startsWith("entity:") && a.predicate === "type" && !a.isSuperseded);
1566
1802
  }
@@ -1592,6 +1828,8 @@ var SubCortexClient = class {
1592
1828
  experiences;
1593
1829
  /** Entity schema management — create, describe, and manage data models */
1594
1830
  entities;
1831
+ /** Code guardrails — typed rules stored as assertions with file-scope matching */
1832
+ rules;
1595
1833
  http;
1596
1834
  constructor(options) {
1597
1835
  if (!options.apiKey && !options.token) {
@@ -1621,13 +1859,14 @@ var SubCortexClient = class {
1621
1859
  this.recall = new RecallNamespace(this.http, options.tenantId);
1622
1860
  this.experiences = new ExperiencesNamespace(this.http, options.tenantId);
1623
1861
  this.entities = new EntitiesNamespace(this.http, options.tenantId);
1862
+ this.rules = new RulesNamespace(this.http, options.tenantId);
1624
1863
  }
1625
1864
  /** Check SubCortex server health. */
1626
1865
  async health() {
1627
1866
  return this.http.get("/health");
1628
1867
  }
1629
1868
  };
1630
- function enc3(s) {
1869
+ function enc4(s) {
1631
1870
  return encodeURIComponent(s);
1632
1871
  }
1633
1872
 
@@ -1816,6 +2055,8 @@ export {
1816
2055
  RecallNamespace,
1817
2056
  RelationshipTypes,
1818
2057
  RelationshipsNamespace,
2058
+ RulePredicates,
2059
+ RulesNamespace,
1819
2060
  SIGNAL_DECAY_CONFIG,
1820
2061
  SYSTEM_SIGNAL_TYPES,
1821
2062
  SearchNamespace,