@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/AGENTS.md +0 -1
- package/README.md +112 -61
- package/dist/cli.cjs +607 -72
- package/dist/cli.js +607 -72
- package/dist/index.cjs +257 -4
- package/dist/index.d.cts +105 -1
- package/dist/index.d.ts +105 -1
- package/dist/index.js +251 -3
- package/package.json +2 -3
- package/.claude/CLAUDE.md +0 -24
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.
|
|
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.
|