@getjack/jack 0.1.30 → 0.1.31
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/package.json +4 -5
- package/src/commands/domain.ts +148 -17
- package/src/commands/domains.ts +28 -2
- package/src/commands/services.ts +300 -1
- package/src/commands/skills.ts +58 -1
- package/src/lib/auth/login-flow.ts +34 -0
- package/src/lib/control-plane.ts +156 -0
- package/src/lib/mcp-config.ts +26 -4
- package/src/lib/output.ts +4 -2
- package/src/lib/picker.ts +3 -1
- package/src/lib/project-operations.ts +38 -4
- package/src/lib/services/cron-create.ts +73 -0
- package/src/lib/services/cron-delete.ts +66 -0
- package/src/lib/services/cron-list.ts +59 -0
- package/src/lib/services/cron-test.ts +93 -0
- package/src/lib/services/cron-utils.ts +78 -0
- package/src/lib/services/domain-operations.ts +89 -18
- package/src/mcp/server.ts +20 -0
- package/src/mcp/tools/index.ts +279 -0
package/src/mcp/tools/index.ts
CHANGED
|
@@ -15,6 +15,10 @@ import {
|
|
|
15
15
|
wrapResultsForMcp,
|
|
16
16
|
} from "../../lib/services/db-execute.ts";
|
|
17
17
|
import { listDatabases } from "../../lib/services/db-list.ts";
|
|
18
|
+
import { createCronSchedule } from "../../lib/services/cron-create.ts";
|
|
19
|
+
import { deleteCronSchedule } from "../../lib/services/cron-delete.ts";
|
|
20
|
+
import { listCronSchedules } from "../../lib/services/cron-list.ts";
|
|
21
|
+
import { testCronExpression } from "../../lib/services/cron-test.ts";
|
|
18
22
|
import {
|
|
19
23
|
assignDomain,
|
|
20
24
|
connectDomain,
|
|
@@ -215,6 +219,42 @@ const DisconnectDomainSchema = z.object({
|
|
|
215
219
|
hostname: z.string().describe("The domain hostname to disconnect (fully remove)"),
|
|
216
220
|
});
|
|
217
221
|
|
|
222
|
+
const CreateCronSchema = z.object({
|
|
223
|
+
expression: z.string().describe("Cron expression (e.g., '0 * * * *' for hourly, '*/15 * * * *' for every 15 min)"),
|
|
224
|
+
project_path: z
|
|
225
|
+
.string()
|
|
226
|
+
.optional()
|
|
227
|
+
.describe("Path to project directory (defaults to current directory)"),
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
const ListCronsSchema = z.object({
|
|
231
|
+
project_path: z
|
|
232
|
+
.string()
|
|
233
|
+
.optional()
|
|
234
|
+
.describe("Path to project directory (defaults to current directory)"),
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
const DeleteCronSchema = z.object({
|
|
238
|
+
expression: z.string().describe("Cron expression to delete"),
|
|
239
|
+
project_path: z
|
|
240
|
+
.string()
|
|
241
|
+
.optional()
|
|
242
|
+
.describe("Path to project directory (defaults to current directory)"),
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
const TestCronSchema = z.object({
|
|
246
|
+
expression: z.string().describe("Cron expression to test"),
|
|
247
|
+
project_path: z
|
|
248
|
+
.string()
|
|
249
|
+
.optional()
|
|
250
|
+
.describe("Path to project directory (defaults to current directory)"),
|
|
251
|
+
trigger_production: z
|
|
252
|
+
.boolean()
|
|
253
|
+
.optional()
|
|
254
|
+
.default(false)
|
|
255
|
+
.describe("Whether to trigger the cron handler on production (requires managed project)"),
|
|
256
|
+
});
|
|
257
|
+
|
|
218
258
|
export function registerTools(server: McpServer, _options: McpServerOptions, debug: DebugLogger) {
|
|
219
259
|
// Register tool list handler
|
|
220
260
|
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
@@ -611,6 +651,80 @@ export function registerTools(server: McpServer, _options: McpServerOptions, deb
|
|
|
611
651
|
required: ["hostname"],
|
|
612
652
|
},
|
|
613
653
|
},
|
|
654
|
+
{
|
|
655
|
+
name: "create_cron",
|
|
656
|
+
description:
|
|
657
|
+
"Create a cron schedule for a managed (Jack Cloud) project. Minimum interval is 15 minutes. The worker must have a scheduled() handler or POST /__scheduled route.",
|
|
658
|
+
inputSchema: {
|
|
659
|
+
type: "object",
|
|
660
|
+
properties: {
|
|
661
|
+
expression: {
|
|
662
|
+
type: "string",
|
|
663
|
+
description: "Cron expression (e.g., '0 * * * *' for hourly, '*/15 * * * *' for every 15 min)",
|
|
664
|
+
},
|
|
665
|
+
project_path: {
|
|
666
|
+
type: "string",
|
|
667
|
+
description: "Path to project directory (defaults to current directory)",
|
|
668
|
+
},
|
|
669
|
+
},
|
|
670
|
+
required: ["expression"],
|
|
671
|
+
},
|
|
672
|
+
},
|
|
673
|
+
{
|
|
674
|
+
name: "list_crons",
|
|
675
|
+
description: "List all cron schedules for a managed (Jack Cloud) project.",
|
|
676
|
+
inputSchema: {
|
|
677
|
+
type: "object",
|
|
678
|
+
properties: {
|
|
679
|
+
project_path: {
|
|
680
|
+
type: "string",
|
|
681
|
+
description: "Path to project directory (defaults to current directory)",
|
|
682
|
+
},
|
|
683
|
+
},
|
|
684
|
+
},
|
|
685
|
+
},
|
|
686
|
+
{
|
|
687
|
+
name: "delete_cron",
|
|
688
|
+
description: "Delete a cron schedule by its expression.",
|
|
689
|
+
inputSchema: {
|
|
690
|
+
type: "object",
|
|
691
|
+
properties: {
|
|
692
|
+
expression: {
|
|
693
|
+
type: "string",
|
|
694
|
+
description: "Cron expression to delete",
|
|
695
|
+
},
|
|
696
|
+
project_path: {
|
|
697
|
+
type: "string",
|
|
698
|
+
description: "Path to project directory (defaults to current directory)",
|
|
699
|
+
},
|
|
700
|
+
},
|
|
701
|
+
required: ["expression"],
|
|
702
|
+
},
|
|
703
|
+
},
|
|
704
|
+
{
|
|
705
|
+
name: "test_cron",
|
|
706
|
+
description:
|
|
707
|
+
"Test a cron expression: validate, show human-readable description, and display next 5 scheduled times. Optionally trigger the handler on production.",
|
|
708
|
+
inputSchema: {
|
|
709
|
+
type: "object",
|
|
710
|
+
properties: {
|
|
711
|
+
expression: {
|
|
712
|
+
type: "string",
|
|
713
|
+
description: "Cron expression to test",
|
|
714
|
+
},
|
|
715
|
+
project_path: {
|
|
716
|
+
type: "string",
|
|
717
|
+
description: "Path to project directory (defaults to current directory)",
|
|
718
|
+
},
|
|
719
|
+
trigger_production: {
|
|
720
|
+
type: "boolean",
|
|
721
|
+
default: false,
|
|
722
|
+
description: "Whether to trigger the cron handler on production (requires managed project)",
|
|
723
|
+
},
|
|
724
|
+
},
|
|
725
|
+
required: ["expression"],
|
|
726
|
+
},
|
|
727
|
+
},
|
|
614
728
|
],
|
|
615
729
|
};
|
|
616
730
|
});
|
|
@@ -1566,6 +1680,171 @@ export function registerTools(server: McpServer, _options: McpServerOptions, deb
|
|
|
1566
1680
|
};
|
|
1567
1681
|
}
|
|
1568
1682
|
|
|
1683
|
+
case "create_cron": {
|
|
1684
|
+
const args = CreateCronSchema.parse(request.params.arguments ?? {});
|
|
1685
|
+
const projectPath = args.project_path ?? process.cwd();
|
|
1686
|
+
|
|
1687
|
+
const wrappedCreateCron = withTelemetry(
|
|
1688
|
+
"create_cron",
|
|
1689
|
+
async (projectDir: string, expression: string) => {
|
|
1690
|
+
const result = await createCronSchedule(projectDir, expression, {
|
|
1691
|
+
interactive: false,
|
|
1692
|
+
});
|
|
1693
|
+
|
|
1694
|
+
track(Events.SERVICE_CREATED, {
|
|
1695
|
+
service_type: "cron",
|
|
1696
|
+
platform: "mcp",
|
|
1697
|
+
});
|
|
1698
|
+
|
|
1699
|
+
return {
|
|
1700
|
+
id: result.id,
|
|
1701
|
+
expression: result.expression,
|
|
1702
|
+
description: result.description,
|
|
1703
|
+
next_run_at: result.nextRunAt,
|
|
1704
|
+
created: result.created,
|
|
1705
|
+
};
|
|
1706
|
+
},
|
|
1707
|
+
{ platform: "mcp" },
|
|
1708
|
+
);
|
|
1709
|
+
|
|
1710
|
+
const result = await wrappedCreateCron(projectPath, args.expression);
|
|
1711
|
+
|
|
1712
|
+
return {
|
|
1713
|
+
content: [
|
|
1714
|
+
{
|
|
1715
|
+
type: "text",
|
|
1716
|
+
text: JSON.stringify(formatSuccessResponse(result, startTime), null, 2),
|
|
1717
|
+
},
|
|
1718
|
+
],
|
|
1719
|
+
};
|
|
1720
|
+
}
|
|
1721
|
+
|
|
1722
|
+
case "list_crons": {
|
|
1723
|
+
const args = ListCronsSchema.parse(request.params.arguments ?? {});
|
|
1724
|
+
const projectPath = args.project_path ?? process.cwd();
|
|
1725
|
+
|
|
1726
|
+
const wrappedListCrons = withTelemetry(
|
|
1727
|
+
"list_crons",
|
|
1728
|
+
async (projectDir: string) => {
|
|
1729
|
+
const schedules = await listCronSchedules(projectDir);
|
|
1730
|
+
return {
|
|
1731
|
+
schedules: schedules.map((s) => ({
|
|
1732
|
+
id: s.id,
|
|
1733
|
+
expression: s.expression,
|
|
1734
|
+
description: s.description,
|
|
1735
|
+
enabled: s.enabled,
|
|
1736
|
+
next_run_at: s.nextRunAt,
|
|
1737
|
+
last_run_at: s.lastRunAt,
|
|
1738
|
+
last_run_status: s.lastRunStatus,
|
|
1739
|
+
last_run_duration_ms: s.lastRunDurationMs,
|
|
1740
|
+
consecutive_failures: s.consecutiveFailures,
|
|
1741
|
+
created_at: s.createdAt,
|
|
1742
|
+
})),
|
|
1743
|
+
};
|
|
1744
|
+
},
|
|
1745
|
+
{ platform: "mcp" },
|
|
1746
|
+
);
|
|
1747
|
+
|
|
1748
|
+
const result = await wrappedListCrons(projectPath);
|
|
1749
|
+
|
|
1750
|
+
return {
|
|
1751
|
+
content: [
|
|
1752
|
+
{
|
|
1753
|
+
type: "text",
|
|
1754
|
+
text: JSON.stringify(formatSuccessResponse(result, startTime), null, 2),
|
|
1755
|
+
},
|
|
1756
|
+
],
|
|
1757
|
+
};
|
|
1758
|
+
}
|
|
1759
|
+
|
|
1760
|
+
case "delete_cron": {
|
|
1761
|
+
const args = DeleteCronSchema.parse(request.params.arguments ?? {});
|
|
1762
|
+
const projectPath = args.project_path ?? process.cwd();
|
|
1763
|
+
|
|
1764
|
+
const wrappedDeleteCron = withTelemetry(
|
|
1765
|
+
"delete_cron",
|
|
1766
|
+
async (projectDir: string, expression: string) => {
|
|
1767
|
+
const result = await deleteCronSchedule(projectDir, expression, {
|
|
1768
|
+
interactive: false,
|
|
1769
|
+
});
|
|
1770
|
+
|
|
1771
|
+
track(Events.SERVICE_DELETED, {
|
|
1772
|
+
service_type: "cron",
|
|
1773
|
+
platform: "mcp",
|
|
1774
|
+
});
|
|
1775
|
+
|
|
1776
|
+
return {
|
|
1777
|
+
expression: result.expression,
|
|
1778
|
+
deleted: result.deleted,
|
|
1779
|
+
};
|
|
1780
|
+
},
|
|
1781
|
+
{ platform: "mcp" },
|
|
1782
|
+
);
|
|
1783
|
+
|
|
1784
|
+
const result = await wrappedDeleteCron(projectPath, args.expression);
|
|
1785
|
+
|
|
1786
|
+
return {
|
|
1787
|
+
content: [
|
|
1788
|
+
{
|
|
1789
|
+
type: "text",
|
|
1790
|
+
text: JSON.stringify(formatSuccessResponse(result, startTime), null, 2),
|
|
1791
|
+
},
|
|
1792
|
+
],
|
|
1793
|
+
};
|
|
1794
|
+
}
|
|
1795
|
+
|
|
1796
|
+
case "test_cron": {
|
|
1797
|
+
const args = TestCronSchema.parse(request.params.arguments ?? {});
|
|
1798
|
+
const projectPath = args.project_path ?? process.cwd();
|
|
1799
|
+
|
|
1800
|
+
const wrappedTestCron = withTelemetry(
|
|
1801
|
+
"test_cron",
|
|
1802
|
+
async (projectDir: string, expression: string, triggerProduction: boolean) => {
|
|
1803
|
+
const result = await testCronExpression(projectDir, expression, {
|
|
1804
|
+
triggerProduction,
|
|
1805
|
+
interactive: false,
|
|
1806
|
+
});
|
|
1807
|
+
|
|
1808
|
+
if (!result.valid) {
|
|
1809
|
+
return {
|
|
1810
|
+
valid: false,
|
|
1811
|
+
error: result.error,
|
|
1812
|
+
};
|
|
1813
|
+
}
|
|
1814
|
+
|
|
1815
|
+
return {
|
|
1816
|
+
valid: true,
|
|
1817
|
+
expression: result.expression,
|
|
1818
|
+
description: result.description,
|
|
1819
|
+
next_times: result.nextTimes?.map((d) => d.toISOString()),
|
|
1820
|
+
trigger_result: result.triggerResult
|
|
1821
|
+
? {
|
|
1822
|
+
triggered: result.triggerResult.triggered,
|
|
1823
|
+
status: result.triggerResult.status,
|
|
1824
|
+
duration_ms: result.triggerResult.durationMs,
|
|
1825
|
+
}
|
|
1826
|
+
: undefined,
|
|
1827
|
+
};
|
|
1828
|
+
},
|
|
1829
|
+
{ platform: "mcp" },
|
|
1830
|
+
);
|
|
1831
|
+
|
|
1832
|
+
const result = await wrappedTestCron(
|
|
1833
|
+
projectPath,
|
|
1834
|
+
args.expression,
|
|
1835
|
+
args.trigger_production ?? false,
|
|
1836
|
+
);
|
|
1837
|
+
|
|
1838
|
+
return {
|
|
1839
|
+
content: [
|
|
1840
|
+
{
|
|
1841
|
+
type: "text",
|
|
1842
|
+
text: JSON.stringify(formatSuccessResponse(result, startTime), null, 2),
|
|
1843
|
+
},
|
|
1844
|
+
],
|
|
1845
|
+
};
|
|
1846
|
+
}
|
|
1847
|
+
|
|
1569
1848
|
default:
|
|
1570
1849
|
throw new Error(`Unknown tool: ${toolName}`);
|
|
1571
1850
|
}
|