opentool 0.7.9 → 0.7.11
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/README.md +6 -1
- package/dist/cli/index.d.ts +3 -2
- package/dist/cli/index.js +101 -2
- package/dist/cli/index.js.map +1 -1
- package/dist/index.d.ts +6 -2
- package/dist/index.js +112 -2
- package/dist/index.js.map +1 -1
- package/dist/store/index.d.ts +41 -0
- package/dist/store/index.js +70 -0
- package/dist/store/index.js.map +1 -0
- package/dist/{validate-BBjyq5nS.d.ts → validate-uetwG5jo.d.ts} +9 -1
- package/package.json +5 -1
package/README.md
CHANGED
|
@@ -82,7 +82,7 @@ export const profile = {
|
|
|
82
82
|
description: "Stake 100 USDC daily at 12:00 UTC",
|
|
83
83
|
fixedAmount: "100",
|
|
84
84
|
tokenSymbol: "USDC",
|
|
85
|
-
schedule: { cron: "0 12 * * *", enabled:
|
|
85
|
+
schedule: { cron: "0 12 * * *", enabled: false },
|
|
86
86
|
limits: { concurrency: 1, dailyCap: 1 },
|
|
87
87
|
};
|
|
88
88
|
|
|
@@ -115,6 +115,11 @@ export async function POST(req: Request) {
|
|
|
115
115
|
}
|
|
116
116
|
```
|
|
117
117
|
|
|
118
|
+
### Cron schedules (`profile.schedule`)
|
|
119
|
+
|
|
120
|
+
- GET-only tools require `profile.schedule` with a standard 5–6 field cron expression (e.g., `0 12 * * *` or `0 0 ? * MON-FRI *`).
|
|
121
|
+
- Build validates the cron shape and emits `.well-known/opentool/cron.json` capturing each scheduled tool (`toolName`, `toolPath`, `scheduleExpression`). Enabled defaults to `false` even if authors set it to `true` in code. Deployment targets can translate these cron strings to their provider format (e.g., EventBridge) downstream.
|
|
122
|
+
|
|
118
123
|
### Public tools: Add x402 payments (optional)
|
|
119
124
|
|
|
120
125
|
Protect your public tools with crypto payments using x402:
|
package/dist/cli/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { M as Metadata, I as InternalToolDefinition } from '../validate-
|
|
3
|
-
export { G as GenerateMetadataOptions, a as GenerateMetadataResult, V as ValidateOptions, b as generateMetadata, g as generateMetadataCommand, l as loadAndValidateTools, v as validateCommand, c as validateFullCommand } from '../validate-
|
|
2
|
+
import { M as Metadata, I as InternalToolDefinition } from '../validate-uetwG5jo.js';
|
|
3
|
+
export { G as GenerateMetadataOptions, a as GenerateMetadataResult, V as ValidateOptions, b as generateMetadata, g as generateMetadataCommand, l as loadAndValidateTools, v as validateCommand, c as validateFullCommand } from '../validate-uetwG5jo.js';
|
|
4
4
|
import 'zod';
|
|
5
5
|
import '../x402/index.js';
|
|
6
6
|
import 'viem';
|
|
@@ -17,6 +17,7 @@ interface BuildArtifacts {
|
|
|
17
17
|
tools: InternalToolDefinition[];
|
|
18
18
|
compiledTools: CompiledToolArtifact[];
|
|
19
19
|
workflowBundles: WorkflowBundleArtifact | null;
|
|
20
|
+
cronManifestPath: string | null;
|
|
20
21
|
}
|
|
21
22
|
interface CompiledToolArtifact {
|
|
22
23
|
name: string;
|
package/dist/cli/index.js
CHANGED
|
@@ -932,6 +932,40 @@ var HTTP_METHODS = [
|
|
|
932
932
|
"OPTIONS"
|
|
933
933
|
];
|
|
934
934
|
|
|
935
|
+
// src/utils/schedule.ts
|
|
936
|
+
var CRON_WRAPPED_REGEX = /^cron\((.*)\)$/i;
|
|
937
|
+
var CRON_TOKEN_REGEX = /^[A-Za-z0-9*?/,\-#L]+$/;
|
|
938
|
+
function normalizeScheduleExpression(raw, context) {
|
|
939
|
+
const value = raw?.trim();
|
|
940
|
+
if (!value) {
|
|
941
|
+
throw new Error(`${context}: profile.schedule.cron must be a non-empty string`);
|
|
942
|
+
}
|
|
943
|
+
const cronBody = extractCronBody(value);
|
|
944
|
+
const cronFields = cronBody.trim().split(/\s+/).filter(Boolean);
|
|
945
|
+
if (cronFields.length !== 5 && cronFields.length !== 6) {
|
|
946
|
+
throw new Error(`${context}: cron expression must have 5 or 6 fields (got ${cronFields.length})`);
|
|
947
|
+
}
|
|
948
|
+
validateCronTokens(cronFields, context);
|
|
949
|
+
return {
|
|
950
|
+
type: "cron",
|
|
951
|
+
expression: cronFields.join(" ")
|
|
952
|
+
};
|
|
953
|
+
}
|
|
954
|
+
function extractCronBody(value) {
|
|
955
|
+
const cronMatch = CRON_WRAPPED_REGEX.exec(value);
|
|
956
|
+
if (cronMatch) {
|
|
957
|
+
return (cronMatch[1] ?? "").trim();
|
|
958
|
+
}
|
|
959
|
+
return value;
|
|
960
|
+
}
|
|
961
|
+
function validateCronTokens(fields, context) {
|
|
962
|
+
fields.forEach((token, idx) => {
|
|
963
|
+
if (!CRON_TOKEN_REGEX.test(token)) {
|
|
964
|
+
throw new Error(`${context}: invalid cron token "${token}" at position ${idx + 1}`);
|
|
965
|
+
}
|
|
966
|
+
});
|
|
967
|
+
}
|
|
968
|
+
|
|
935
969
|
// src/cli/validate.ts
|
|
936
970
|
var SUPPORTED_EXTENSIONS = [
|
|
937
971
|
".ts",
|
|
@@ -1051,11 +1085,16 @@ async function loadAndValidateTools(toolsDir, options = {}) {
|
|
|
1051
1085
|
if (hasGET === hasPOST) {
|
|
1052
1086
|
throw new Error(`${file}: export exactly one of GET or POST`);
|
|
1053
1087
|
}
|
|
1088
|
+
let normalizedSchedule = null;
|
|
1054
1089
|
if (hasGET) {
|
|
1055
1090
|
const schedule = toolModule?.profile?.schedule;
|
|
1056
1091
|
if (!schedule || typeof schedule?.cron !== "string" || schedule.cron.trim().length === 0) {
|
|
1057
1092
|
throw new Error(`${file}: GET tools require profile.schedule { cron }`);
|
|
1058
1093
|
}
|
|
1094
|
+
normalizedSchedule = normalizeScheduleExpression(schedule.cron, file);
|
|
1095
|
+
if (typeof schedule.enabled === "boolean") {
|
|
1096
|
+
normalizedSchedule.authoredEnabled = schedule.enabled;
|
|
1097
|
+
}
|
|
1059
1098
|
}
|
|
1060
1099
|
if (hasPOST) {
|
|
1061
1100
|
if (!schema) {
|
|
@@ -1112,7 +1151,9 @@ async function loadAndValidateTools(toolsDir, options = {}) {
|
|
|
1112
1151
|
filename: toBaseName(file),
|
|
1113
1152
|
sourcePath: path5.join(toolsDir, file),
|
|
1114
1153
|
handler: async (params) => adapter(params),
|
|
1115
|
-
payment: paymentExport ?? null
|
|
1154
|
+
payment: paymentExport ?? null,
|
|
1155
|
+
schedule: normalizedSchedule,
|
|
1156
|
+
profileDescription: typeof toolModule?.profile?.description === "string" ? toolModule.profile?.description ?? null : null
|
|
1116
1157
|
};
|
|
1117
1158
|
tools.push(tool);
|
|
1118
1159
|
}
|
|
@@ -1334,6 +1375,11 @@ async function buildProject(options) {
|
|
|
1334
1375
|
projectRoot,
|
|
1335
1376
|
outputDir
|
|
1336
1377
|
});
|
|
1378
|
+
const cronManifestPath = await writeCronManifest({
|
|
1379
|
+
tools,
|
|
1380
|
+
compiledTools,
|
|
1381
|
+
outputDir
|
|
1382
|
+
});
|
|
1337
1383
|
const workflowBundles = await buildWorkflowsIfPresent({
|
|
1338
1384
|
projectRoot,
|
|
1339
1385
|
outputDir
|
|
@@ -1356,7 +1402,8 @@ async function buildProject(options) {
|
|
|
1356
1402
|
defaultsApplied,
|
|
1357
1403
|
tools,
|
|
1358
1404
|
compiledTools,
|
|
1359
|
-
workflowBundles
|
|
1405
|
+
workflowBundles,
|
|
1406
|
+
cronManifestPath
|
|
1360
1407
|
};
|
|
1361
1408
|
}
|
|
1362
1409
|
async function emitTools(tools, config) {
|
|
@@ -1499,6 +1546,55 @@ async function writeMcpServer(options) {
|
|
|
1499
1546
|
fs4.writeFileSync(serverPath, serverCode);
|
|
1500
1547
|
fs4.chmodSync(serverPath, 493);
|
|
1501
1548
|
}
|
|
1549
|
+
function writeCronManifest(options) {
|
|
1550
|
+
const scheduledTools = options.tools.filter((tool) => tool.schedule?.expression);
|
|
1551
|
+
const manifestDir = path5.join(options.outputDir, ".well-known", "opentool");
|
|
1552
|
+
const manifestPath = path5.join(manifestDir, "cron.json");
|
|
1553
|
+
if (scheduledTools.length === 0) {
|
|
1554
|
+
if (fs4.existsSync(manifestPath)) {
|
|
1555
|
+
fs4.rmSync(manifestPath);
|
|
1556
|
+
}
|
|
1557
|
+
return null;
|
|
1558
|
+
}
|
|
1559
|
+
const entries = scheduledTools.map((tool) => {
|
|
1560
|
+
const schedule = tool.schedule;
|
|
1561
|
+
if (!schedule) {
|
|
1562
|
+
throw new Error(`Internal error: missing schedule for tool ${tool.filename}`);
|
|
1563
|
+
}
|
|
1564
|
+
const compiled = options.compiledTools.find(
|
|
1565
|
+
(artifact) => artifact.filename === tool.filename
|
|
1566
|
+
);
|
|
1567
|
+
if (!compiled) {
|
|
1568
|
+
throw new Error(`Internal error: missing compiled artifact for ${tool.filename}`);
|
|
1569
|
+
}
|
|
1570
|
+
const toolName = tool.metadata?.name ?? tool.filename;
|
|
1571
|
+
const description = tool.metadata?.description ?? tool.profileDescription ?? void 0;
|
|
1572
|
+
const payloadPath = compiled.modulePath.replace(/\\/g, "/");
|
|
1573
|
+
const entry = {
|
|
1574
|
+
toolName,
|
|
1575
|
+
scheduleType: schedule.type,
|
|
1576
|
+
scheduleExpression: schedule.expression,
|
|
1577
|
+
enabledDefault: false,
|
|
1578
|
+
...schedule.authoredEnabled !== void 0 ? { authoredEnabled: schedule.authoredEnabled } : {},
|
|
1579
|
+
payload: {
|
|
1580
|
+
toolPath: payloadPath,
|
|
1581
|
+
httpMethod: "GET"
|
|
1582
|
+
}
|
|
1583
|
+
};
|
|
1584
|
+
if (description !== void 0) {
|
|
1585
|
+
entry.description = description;
|
|
1586
|
+
}
|
|
1587
|
+
return entry;
|
|
1588
|
+
});
|
|
1589
|
+
const manifest = {
|
|
1590
|
+
version: 1,
|
|
1591
|
+
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1592
|
+
entries
|
|
1593
|
+
};
|
|
1594
|
+
fs4.mkdirSync(manifestDir, { recursive: true });
|
|
1595
|
+
fs4.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2));
|
|
1596
|
+
return manifestPath;
|
|
1597
|
+
}
|
|
1502
1598
|
function logBuildSummary(artifacts, options) {
|
|
1503
1599
|
const end = timestamp();
|
|
1504
1600
|
console.log(`[${end}] Build completed successfully!`);
|
|
@@ -1515,6 +1611,9 @@ function logBuildSummary(artifacts, options) {
|
|
|
1515
1611
|
console.log(` - ${tool.name} [${methods}]${walletBadge}`);
|
|
1516
1612
|
});
|
|
1517
1613
|
console.log(" \u2022 metadata.json (registry artifact)");
|
|
1614
|
+
if (artifacts.cronManifestPath) {
|
|
1615
|
+
console.log(" \u2022 .well-known/opentool/cron.json (cron manifest)");
|
|
1616
|
+
}
|
|
1518
1617
|
if (artifacts.workflowBundles) {
|
|
1519
1618
|
console.log(" \u2022 .well-known/workflow/v1/ (workflow bundles)");
|
|
1520
1619
|
console.log(" - flow.js");
|