@agentcash/discovery 0.1.0 → 0.1.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
@@ -11,6 +11,9 @@ var STRICT_ESCALATION_CODES = [
11
11
  "INTEROP_MPP_USED"
12
12
  ];
13
13
 
14
+ // src/mmm-enabled.ts
15
+ var isMmmEnabled = () => "0.1.1".includes("-mmm");
16
+
14
17
  // src/core/constants.ts
15
18
  var OPENAPI_PATH_CANDIDATES = ["/openapi.json", "/.well-known/openapi.json"];
16
19
  var WELL_KNOWN_MPP_PATH = "/.well-known/mpp";
@@ -963,7 +966,7 @@ function detectProtocols(response) {
963
966
  }
964
967
  const authHeader = response.headers.get("www-authenticate")?.toLowerCase() ?? "";
965
968
  if (authHeader.includes("x402")) protocols.add("x402");
966
- if (authHeader.includes("mpp")) protocols.add("mpp");
969
+ if (isMmmEnabled() && authHeader.includes("mpp")) protocols.add("mpp");
967
970
  return [...protocols];
968
971
  }
969
972
  async function runProbeStage(options) {
@@ -1295,7 +1298,7 @@ async function runDiscovery({
1295
1298
  includeRaw
1296
1299
  })
1297
1300
  );
1298
- if (includeInteropMpp) {
1301
+ if (includeInteropMpp && isMmmEnabled()) {
1299
1302
  stages.push(
1300
1303
  () => runInteropMppStage({
1301
1304
  origin,
@@ -1397,6 +1400,246 @@ async function runDiscovery({
1397
1400
  };
1398
1401
  }
1399
1402
 
1403
+ // src/harness.ts
1404
+ var INTENT_TRIGGERS = ["x402", "mpp", "pay for", "micropayment", "agentic commerce"];
1405
+ var CLIENT_PROFILES = {
1406
+ "claude-code": {
1407
+ id: "claude-code",
1408
+ label: "Claude Code MCP Harness",
1409
+ surface: "mcp",
1410
+ defaultContextWindowTokens: 2e5,
1411
+ zeroHopBudgetPercent: 0.1,
1412
+ notes: "Targets environments where MCP context can use roughly 10% of total context."
1413
+ },
1414
+ "skill-cli": {
1415
+ id: "skill-cli",
1416
+ label: "Skill + CLI Harness",
1417
+ surface: "skill-cli",
1418
+ defaultContextWindowTokens: 2e5,
1419
+ zeroHopBudgetPercent: 0.02,
1420
+ notes: "Targets constrained skill contexts with title/description-heavy routing."
1421
+ },
1422
+ "generic-mcp": {
1423
+ id: "generic-mcp",
1424
+ label: "Generic MCP Harness",
1425
+ surface: "mcp",
1426
+ defaultContextWindowTokens: 128e3,
1427
+ zeroHopBudgetPercent: 0.05,
1428
+ notes: "Conservative MCP profile when specific client budgets are unknown."
1429
+ },
1430
+ generic: {
1431
+ id: "generic",
1432
+ label: "Generic Agent Harness",
1433
+ surface: "generic",
1434
+ defaultContextWindowTokens: 128e3,
1435
+ zeroHopBudgetPercent: 0.03,
1436
+ notes: "Fallback profile for unknown clients."
1437
+ }
1438
+ };
1439
+ function isFirstPartyDomain(hostname) {
1440
+ const normalized = hostname.toLowerCase();
1441
+ return normalized.endsWith(".dev") && normalized.startsWith("stable");
1442
+ }
1443
+ function safeHostname(origin) {
1444
+ try {
1445
+ return new URL(origin).hostname;
1446
+ } catch {
1447
+ return origin.replace(/^https?:\/\//, "").split("/")[0] ?? origin;
1448
+ }
1449
+ }
1450
+ function previewText(text) {
1451
+ if (!text) return null;
1452
+ const compact = text.replace(/\s+/g, " ").trim();
1453
+ if (!compact) return null;
1454
+ return compact.length > 220 ? `${compact.slice(0, 217)}...` : compact;
1455
+ }
1456
+ function toAuthModeCount(resources) {
1457
+ const counts = {
1458
+ paid: 0,
1459
+ siwx: 0,
1460
+ apiKey: 0,
1461
+ unprotected: 0,
1462
+ unknown: 0
1463
+ };
1464
+ for (const resource of resources) {
1465
+ const mode = resource.authHint;
1466
+ if (mode === "paid" || mode === "siwx" || mode === "apiKey" || mode === "unprotected") {
1467
+ counts[mode] += 1;
1468
+ } else {
1469
+ counts.unknown += 1;
1470
+ }
1471
+ }
1472
+ return counts;
1473
+ }
1474
+ function toSourceCount(resources) {
1475
+ return resources.reduce(
1476
+ (acc, resource) => {
1477
+ acc[resource.source] = (acc[resource.source] ?? 0) + 1;
1478
+ return acc;
1479
+ },
1480
+ {}
1481
+ );
1482
+ }
1483
+ function toL2Entries(resources) {
1484
+ return [...resources].sort((a, b) => {
1485
+ if (a.path !== b.path) return a.path.localeCompare(b.path);
1486
+ if (a.method !== b.method) return a.method.localeCompare(b.method);
1487
+ return a.resourceKey.localeCompare(b.resourceKey);
1488
+ }).map((resource) => ({
1489
+ resourceKey: resource.resourceKey,
1490
+ method: resource.method,
1491
+ path: resource.path,
1492
+ source: resource.source,
1493
+ authMode: resource.authHint ?? null
1494
+ }));
1495
+ }
1496
+ function getLlmsTxtInfo(result) {
1497
+ const llmsTxtUrl = result.trace.find((entry) => entry.links?.llmsTxtUrl)?.links?.llmsTxtUrl ?? result.resources.find((resource) => resource.links?.llmsTxtUrl)?.links?.llmsTxtUrl ?? null;
1498
+ const llmsTxt = result.rawSources?.llmsTxt;
1499
+ if (llmsTxt) {
1500
+ return {
1501
+ llmsTxtUrl,
1502
+ llmsTxtTokenEstimate: estimateTokenCount(llmsTxt),
1503
+ guidancePreview: previewText(llmsTxt),
1504
+ guidanceStatus: "present"
1505
+ };
1506
+ }
1507
+ if (llmsTxtUrl) {
1508
+ const failed = result.warnings.some((warning2) => warning2.code === "LLMSTXT_FETCH_FAILED");
1509
+ return {
1510
+ llmsTxtUrl,
1511
+ llmsTxtTokenEstimate: 0,
1512
+ guidancePreview: null,
1513
+ guidanceStatus: failed ? "advertised_but_unfetched" : "missing"
1514
+ };
1515
+ }
1516
+ return {
1517
+ llmsTxtUrl: null,
1518
+ llmsTxtTokenEstimate: 0,
1519
+ guidancePreview: null,
1520
+ guidanceStatus: "not_advertised"
1521
+ };
1522
+ }
1523
+ function getHarnessClientProfile(client = "claude-code") {
1524
+ return CLIENT_PROFILES[client] ?? CLIENT_PROFILES.generic;
1525
+ }
1526
+ function listHarnessClientProfiles() {
1527
+ return Object.values(CLIENT_PROFILES);
1528
+ }
1529
+ function buildContextHarnessReport(options) {
1530
+ const client = getHarnessClientProfile(options.client);
1531
+ const contextWindowTokens = options.contextWindowTokens ?? client.defaultContextWindowTokens;
1532
+ const zeroHopBudgetTokens = Math.floor(contextWindowTokens * client.zeroHopBudgetPercent);
1533
+ const hostname = safeHostname(options.result.origin);
1534
+ const domainClass = isFirstPartyDomain(hostname) ? "first-party" : "ugc";
1535
+ const l0Summary = "Route payment-capable intents to agentcash and use install/discover commands for progressive disclosure.";
1536
+ const l1Summary = "Expose installed domain routing hints and trigger fan-out into L2/L3 commands when user intent matches domain capabilities.";
1537
+ const l0EstimatedTokens = estimateTokenCount(
1538
+ `${INTENT_TRIGGERS.join(", ")} npx agentcash install npx agentcash install-ext`
1539
+ );
1540
+ const l1EstimatedTokens = estimateTokenCount(
1541
+ `${hostname} ${l1Summary} npx agentcash discover ${hostname} npx agentcash discover ${hostname} --verbose`
1542
+ );
1543
+ const llmsInfo = getLlmsTxtInfo(options.result);
1544
+ return {
1545
+ target: options.target,
1546
+ origin: options.result.origin,
1547
+ client,
1548
+ budget: {
1549
+ contextWindowTokens,
1550
+ zeroHopBudgetTokens,
1551
+ estimatedZeroHopTokens: l0EstimatedTokens + l1EstimatedTokens,
1552
+ withinBudget: l0EstimatedTokens + l1EstimatedTokens <= zeroHopBudgetTokens
1553
+ },
1554
+ levels: {
1555
+ l0: {
1556
+ layer: "L0",
1557
+ intentTriggers: INTENT_TRIGGERS,
1558
+ installCommand: "npx agentcash install",
1559
+ deliverySurfaces: ["MCP", "Skill+CLI"],
1560
+ summary: l0Summary,
1561
+ estimatedTokens: l0EstimatedTokens
1562
+ },
1563
+ l1: {
1564
+ layer: "L1",
1565
+ domain: hostname,
1566
+ domainClass,
1567
+ selectedDiscoveryStage: options.result.selectedStage ?? null,
1568
+ summary: l1Summary,
1569
+ fanoutCommands: [
1570
+ `npx agentcash discover ${hostname}`,
1571
+ `npx agentcash discover ${hostname} --verbose`
1572
+ ],
1573
+ estimatedTokens: l1EstimatedTokens
1574
+ },
1575
+ l2: {
1576
+ layer: "L2",
1577
+ command: `npx agentcash discover ${hostname}`,
1578
+ tokenLight: true,
1579
+ resourceCount: options.result.resources.length,
1580
+ resources: toL2Entries(options.result.resources)
1581
+ },
1582
+ l3: {
1583
+ layer: "L3",
1584
+ command: `npx agentcash discover ${hostname} --verbose`,
1585
+ detailLevel: "endpoint-schema-and-metadata",
1586
+ countsByAuthMode: toAuthModeCount(options.result.resources),
1587
+ countsBySource: toSourceCount(options.result.resources),
1588
+ pricedResourceCount: options.result.resources.filter(
1589
+ (resource) => resource.authHint === "paid"
1590
+ ).length
1591
+ },
1592
+ l4: {
1593
+ layer: "L4",
1594
+ guidanceSource: llmsInfo.llmsTxtUrl ? "llms.txt" : "none",
1595
+ llmsTxtUrl: llmsInfo.llmsTxtUrl,
1596
+ llmsTxtTokenEstimate: llmsInfo.llmsTxtTokenEstimate,
1597
+ guidancePreview: llmsInfo.guidancePreview,
1598
+ guidanceStatus: llmsInfo.guidanceStatus
1599
+ },
1600
+ l5: {
1601
+ layer: "L5",
1602
+ status: "out_of_scope",
1603
+ note: "Cross-domain composition is intentionally out of scope for discovery v1."
1604
+ }
1605
+ },
1606
+ diagnostics: {
1607
+ warningCount: options.result.warnings.length,
1608
+ errorWarningCount: options.result.warnings.filter((warning2) => warning2.severity === "error").length,
1609
+ selectedStage: options.result.selectedStage ?? null,
1610
+ upgradeSuggested: options.result.upgradeSuggested,
1611
+ upgradeReasons: options.result.upgradeReasons
1612
+ }
1613
+ };
1614
+ }
1615
+ async function auditContextHarness(options) {
1616
+ const result = await runDiscovery({
1617
+ detailed: true,
1618
+ options: {
1619
+ ...options,
1620
+ rawView: "full"
1621
+ }
1622
+ });
1623
+ return buildContextHarnessReport({
1624
+ target: options.target,
1625
+ result,
1626
+ client: options.client,
1627
+ contextWindowTokens: options.contextWindowTokens
1628
+ });
1629
+ }
1630
+ function defaultHarnessProbeCandidates(report) {
1631
+ const methodsByPath = /* @__PURE__ */ new Map();
1632
+ for (const resource of report.levels.l2.resources) {
1633
+ const methods = methodsByPath.get(resource.path) ?? /* @__PURE__ */ new Set();
1634
+ methods.add(resource.method);
1635
+ methodsByPath.set(resource.path, methods);
1636
+ }
1637
+ return [...methodsByPath.entries()].map(([path, methods]) => ({
1638
+ path,
1639
+ methods: [...methods]
1640
+ }));
1641
+ }
1642
+
1400
1643
  // src/index.ts
1401
1644
  async function discover(options) {
1402
1645
  return await runDiscovery({ detailed: false, options });
@@ -1409,7 +1652,12 @@ export {
1409
1652
  LEGACY_SUNSET_DATE,
1410
1653
  STRICT_ESCALATION_CODES,
1411
1654
  UPGRADE_WARNING_CODES,
1655
+ auditContextHarness,
1656
+ buildContextHarnessReport,
1412
1657
  computeUpgradeSignal,
1658
+ defaultHarnessProbeCandidates,
1413
1659
  discover,
1414
- discoverDetailed
1660
+ discoverDetailed,
1661
+ getHarnessClientProfile,
1662
+ listHarnessClientProfiles
1415
1663
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentcash/discovery",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Canonical OpenAPI-first discovery runtime for the agentcash ecosystem",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -44,7 +44,6 @@
44
44
  "bin",
45
45
  "README.md",
46
46
  "LICENSE",
47
- ".claude/CLAUDE.md",
48
47
  "AGENTS.md"
49
48
  ],
50
49
  "engines": {
@@ -54,7 +53,6 @@
54
53
  "agentcash",
55
54
  "discovery",
56
55
  "x402",
57
- "mpp",
58
56
  "openapi"
59
57
  ],
60
58
  "license": "MIT",
@@ -66,6 +64,7 @@
66
64
  "access": "public"
67
65
  },
68
66
  "dependencies": {
67
+ "table": "^6.9.0",
69
68
  "zod": "^4.1.13"
70
69
  },
71
70
  "devDependencies": {
package/.claude/CLAUDE.md DELETED
@@ -1,24 +0,0 @@
1
- # CLAUDE.md
2
-
3
- This package is the canonical discovery runtime for agentcash.
4
-
5
- ## Core decisions
6
-
7
- - OpenAPI is canonical machine discovery source.
8
- - Discovery order: override -> OpenAPI -> `/.well-known/x402` -> DNS `_x402` -> probe.
9
- - `discover` is progressive and token-light.
10
- - `discoverDetailed` is full-waterfall with trace.
11
- - Compatibility adapters are isolated and removable.
12
- - `llms.txt` is unstructured guidance only; OpenAPI carries machine metadata.
13
-
14
- ## Important defaults
15
-
16
- - `compatMode = on` (until legacy sunset window ends).
17
- - `verified = false` in advisory output.
18
- - `trustTier` values: `unverified | origin_hosted | ownership_verified | runtime_verified`.
19
-
20
- ## Do not do
21
-
22
- - Do not leak legacy branches into canonical parser logic.
23
- - Do not introduce hidden fallback passes.
24
- - Do not change warning codes without a breaking version decision.