@framers/agentos-ext-cloud-digitalocean 0.1.0

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.
Files changed (47) hide show
  1. package/LICENSE +98 -0
  2. package/dist/DigitalOceanService.d.ts +215 -0
  3. package/dist/DigitalOceanService.d.ts.map +1 -0
  4. package/dist/DigitalOceanService.js +323 -0
  5. package/dist/DigitalOceanService.js.map +1 -0
  6. package/dist/index.d.ts +43 -0
  7. package/dist/index.d.ts.map +1 -0
  8. package/dist/index.js +74 -0
  9. package/dist/index.js.map +1 -0
  10. package/dist/tools/createApp.d.ts +79 -0
  11. package/dist/tools/createApp.d.ts.map +1 -0
  12. package/dist/tools/createApp.js +54 -0
  13. package/dist/tools/createApp.js.map +1 -0
  14. package/dist/tools/createDroplet.d.ts +80 -0
  15. package/dist/tools/createDroplet.d.ts.map +1 -0
  16. package/dist/tools/createDroplet.js +60 -0
  17. package/dist/tools/createDroplet.js.map +1 -0
  18. package/dist/tools/deleteResource.d.ts +42 -0
  19. package/dist/tools/deleteResource.d.ts.map +1 -0
  20. package/dist/tools/deleteResource.js +56 -0
  21. package/dist/tools/deleteResource.js.map +1 -0
  22. package/dist/tools/deployApp.d.ts +39 -0
  23. package/dist/tools/deployApp.d.ts.map +1 -0
  24. package/dist/tools/deployApp.js +35 -0
  25. package/dist/tools/deployApp.js.map +1 -0
  26. package/dist/tools/listResources.d.ts +54 -0
  27. package/dist/tools/listResources.d.ts.map +1 -0
  28. package/dist/tools/listResources.js +50 -0
  29. package/dist/tools/listResources.js.map +1 -0
  30. package/dist/tools/manageDns.d.ts +82 -0
  31. package/dist/tools/manageDns.d.ts.map +1 -0
  32. package/dist/tools/manageDns.js +107 -0
  33. package/dist/tools/manageDns.js.map +1 -0
  34. package/manifest.json +35 -0
  35. package/package.json +65 -0
  36. package/src/DigitalOceanService.ts +514 -0
  37. package/src/index.ts +130 -0
  38. package/src/tools/createApp.ts +69 -0
  39. package/src/tools/createDroplet.ts +74 -0
  40. package/src/tools/deleteResource.ts +64 -0
  41. package/src/tools/deployApp.ts +41 -0
  42. package/src/tools/listResources.ts +66 -0
  43. package/src/tools/manageDns.ts +131 -0
  44. package/test/DigitalOceanService.test.ts +435 -0
  45. package/test/index.test.ts +58 -0
  46. package/test/tools.test.ts +478 -0
  47. package/tsconfig.json +22 -0
@@ -0,0 +1,74 @@
1
+ // @ts-nocheck
2
+ /**
3
+ * @fileoverview DOCreateDropletTool — create a VPS Droplet with specified region, size, and image.
4
+ */
5
+
6
+ import type { DigitalOceanService, DODroplet } from '../DigitalOceanService.js';
7
+
8
+ export interface CreateDropletInput {
9
+ name: string;
10
+ region: string;
11
+ size: string;
12
+ image: string;
13
+ sshKeys?: (string | number)[];
14
+ userData?: string;
15
+ backups?: boolean;
16
+ ipv6?: boolean;
17
+ tags?: string[];
18
+ }
19
+
20
+ export class DOCreateDropletTool {
21
+ readonly id = 'doCreateDroplet';
22
+ readonly name = 'doCreateDroplet';
23
+ readonly displayName = 'Create DO Droplet';
24
+ readonly description = 'Create a DigitalOcean Droplet (VPS instance) with a specified region, size, and OS image. Supports SSH key injection, cloud-init user data scripts, backups, IPv6, and tagging.';
25
+ readonly category = 'cloud';
26
+ readonly version = '0.1.0';
27
+ readonly hasSideEffects = true;
28
+
29
+ readonly inputSchema = {
30
+ type: 'object' as const,
31
+ properties: {
32
+ name: { type: 'string', description: 'Droplet hostname (e.g. "my-server-01")' },
33
+ region: { type: 'string', description: 'Region slug (e.g. "nyc1", "sfo3", "ams3", "sgp1", "lon1")' },
34
+ size: { type: 'string', description: 'Size slug (e.g. "s-1vcpu-1gb", "s-2vcpu-4gb", "s-4vcpu-8gb")' },
35
+ image: { type: 'string', description: 'Image slug or ID (e.g. "ubuntu-24-04-x64", "debian-12-x64", "docker-20-04")' },
36
+ sshKeys: {
37
+ type: 'array',
38
+ items: { type: ['string', 'number'] },
39
+ description: 'SSH key IDs or fingerprints to embed in the Droplet',
40
+ },
41
+ userData: { type: 'string', description: 'Cloud-init user data script for automated setup' },
42
+ backups: { type: 'boolean', description: 'Enable weekly backups (default: false)' },
43
+ ipv6: { type: 'boolean', description: 'Enable IPv6 networking (default: false)' },
44
+ tags: {
45
+ type: 'array',
46
+ items: { type: 'string' },
47
+ description: 'Tags to apply to the Droplet for organization and filtering',
48
+ },
49
+ },
50
+ required: ['name', 'region', 'size', 'image'],
51
+ };
52
+
53
+ constructor(private service: DigitalOceanService) {}
54
+
55
+ async execute(args: CreateDropletInput): Promise<{ success: boolean; data?: DODroplet; error?: string }> {
56
+ try {
57
+ const droplet = await this.service.createDroplet({
58
+ name: args.name,
59
+ region: args.region,
60
+ size: args.size,
61
+ image: args.image,
62
+ sshKeys: args.sshKeys,
63
+ userData: args.userData,
64
+ backups: args.backups,
65
+ ipv6: args.ipv6,
66
+ tags: args.tags,
67
+ });
68
+
69
+ return { success: true, data: droplet };
70
+ } catch (err: any) {
71
+ return { success: false, error: err.message };
72
+ }
73
+ }
74
+ }
@@ -0,0 +1,64 @@
1
+ // @ts-nocheck
2
+ /**
3
+ * @fileoverview DODeleteResourceTool — delete an app or droplet from DigitalOcean.
4
+ */
5
+
6
+ import type { DigitalOceanService } from '../DigitalOceanService.js';
7
+
8
+ export interface DeleteResourceInput {
9
+ resourceType: 'app' | 'droplet';
10
+ resourceId: string;
11
+ }
12
+
13
+ export class DODeleteResourceTool {
14
+ readonly id = 'doDeleteResource';
15
+ readonly name = 'doDeleteResource';
16
+ readonly displayName = 'Delete DO Resource';
17
+ readonly description = 'Permanently delete a DigitalOcean App Platform app or Droplet. This action is irreversible — the resource and all associated data will be destroyed.';
18
+ readonly category = 'cloud';
19
+ readonly version = '0.1.0';
20
+ readonly hasSideEffects = true;
21
+
22
+ readonly inputSchema = {
23
+ type: 'object' as const,
24
+ properties: {
25
+ resourceType: {
26
+ type: 'string',
27
+ enum: ['app', 'droplet'],
28
+ description: 'Type of resource to delete',
29
+ },
30
+ resourceId: {
31
+ type: 'string',
32
+ description: 'Resource ID to delete (app UUID or droplet numeric ID)',
33
+ },
34
+ },
35
+ required: ['resourceType', 'resourceId'],
36
+ };
37
+
38
+ constructor(private service: DigitalOceanService) {}
39
+
40
+ async execute(args: DeleteResourceInput): Promise<{ success: boolean; data?: { message: string }; error?: string }> {
41
+ try {
42
+ switch (args.resourceType) {
43
+ case 'app': {
44
+ await this.service.deleteApp(args.resourceId);
45
+ return { success: true, data: { message: `App ${args.resourceId} has been deleted.` } };
46
+ }
47
+
48
+ case 'droplet': {
49
+ const dropletId = parseInt(args.resourceId, 10);
50
+ if (isNaN(dropletId)) {
51
+ return { success: false, error: `Invalid droplet ID: "${args.resourceId}". Must be a numeric ID.` };
52
+ }
53
+ await this.service.deleteDroplet(dropletId);
54
+ return { success: true, data: { message: `Droplet ${dropletId} has been deleted.` } };
55
+ }
56
+
57
+ default:
58
+ return { success: false, error: `Unknown resource type: ${args.resourceType}. Use "app" or "droplet".` };
59
+ }
60
+ } catch (err: any) {
61
+ return { success: false, error: err.message };
62
+ }
63
+ }
64
+ }
@@ -0,0 +1,41 @@
1
+ // @ts-nocheck
2
+ /**
3
+ * @fileoverview DODeployAppTool — trigger a new deployment on an existing App Platform app.
4
+ */
5
+
6
+ import type { DigitalOceanService, DODeployment } from '../DigitalOceanService.js';
7
+
8
+ export interface DeployAppInput {
9
+ appId: string;
10
+ forceBuild?: boolean;
11
+ }
12
+
13
+ export class DODeployAppTool {
14
+ readonly id = 'doDeployApp';
15
+ readonly name = 'doDeployApp';
16
+ readonly displayName = 'Deploy DO App';
17
+ readonly description = 'Trigger a new deployment on an existing DigitalOcean App Platform app. Pulls the latest code from the configured Git repository and builds/deploys it. Optionally force a full rebuild.';
18
+ readonly category = 'cloud';
19
+ readonly version = '0.1.0';
20
+ readonly hasSideEffects = true;
21
+
22
+ readonly inputSchema = {
23
+ type: 'object' as const,
24
+ properties: {
25
+ appId: { type: 'string', description: 'App ID to deploy (use doListResources to find app IDs)' },
26
+ forceBuild: { type: 'boolean', description: 'Force a complete rebuild instead of incremental (default: false)' },
27
+ },
28
+ required: ['appId'],
29
+ };
30
+
31
+ constructor(private service: DigitalOceanService) {}
32
+
33
+ async execute(args: DeployAppInput): Promise<{ success: boolean; data?: DODeployment; error?: string }> {
34
+ try {
35
+ const deployment = await this.service.createDeployment(args.appId, args.forceBuild);
36
+ return { success: true, data: deployment };
37
+ } catch (err: any) {
38
+ return { success: false, error: err.message };
39
+ }
40
+ }
41
+ }
@@ -0,0 +1,66 @@
1
+ // @ts-nocheck
2
+ /**
3
+ * @fileoverview DOListResourcesTool — list all apps and/or droplets on a DigitalOcean account.
4
+ */
5
+
6
+ import type { DigitalOceanService, DOApp, DODroplet } from '../DigitalOceanService.js';
7
+
8
+ export interface ListResourcesInput {
9
+ resourceType?: 'apps' | 'droplets' | 'all';
10
+ page?: number;
11
+ perPage?: number;
12
+ tag?: string;
13
+ }
14
+
15
+ export interface ListResourcesResult {
16
+ apps?: DOApp[];
17
+ droplets?: DODroplet[];
18
+ }
19
+
20
+ export class DOListResourcesTool {
21
+ readonly id = 'doListResources';
22
+ readonly name = 'doListResources';
23
+ readonly displayName = 'List DO Resources';
24
+ readonly description = 'List all DigitalOcean App Platform apps and/or Droplets. Filter by resource type (apps, droplets, or both) and optionally by tag. Returns names, statuses, regions, IPs, and deployment info.';
25
+ readonly category = 'cloud';
26
+ readonly version = '0.1.0';
27
+ readonly hasSideEffects = false;
28
+
29
+ readonly inputSchema = {
30
+ type: 'object' as const,
31
+ properties: {
32
+ resourceType: {
33
+ type: 'string',
34
+ enum: ['apps', 'droplets', 'all'],
35
+ description: 'Which resource type to list (default: "all")',
36
+ },
37
+ page: { type: 'number', description: 'Page number for pagination (default: 1)' },
38
+ perPage: { type: 'number', description: 'Items per page (default: 20, max: 200)' },
39
+ tag: { type: 'string', description: 'Filter droplets by tag name' },
40
+ },
41
+ required: [] as string[],
42
+ };
43
+
44
+ constructor(private service: DigitalOceanService) {}
45
+
46
+ async execute(args: ListResourcesInput): Promise<{ success: boolean; data?: ListResourcesResult; error?: string }> {
47
+ try {
48
+ const resourceType = args.resourceType ?? 'all';
49
+ const page = args.page ?? 1;
50
+ const perPage = args.perPage ?? 20;
51
+ const result: ListResourcesResult = {};
52
+
53
+ if (resourceType === 'apps' || resourceType === 'all') {
54
+ result.apps = await this.service.listApps(page, perPage);
55
+ }
56
+
57
+ if (resourceType === 'droplets' || resourceType === 'all') {
58
+ result.droplets = await this.service.listDroplets(page, perPage, args.tag);
59
+ }
60
+
61
+ return { success: true, data: result };
62
+ } catch (err: any) {
63
+ return { success: false, error: err.message };
64
+ }
65
+ }
66
+ }
@@ -0,0 +1,131 @@
1
+ // @ts-nocheck
2
+ /**
3
+ * @fileoverview DOManageDnsTool — manage DNS records on a DigitalOcean domain.
4
+ */
5
+
6
+ import type { DigitalOceanService, DODomain, DODomainRecord } from '../DigitalOceanService.js';
7
+
8
+ export interface ManageDnsInput {
9
+ action: 'list-domains' | 'add-domain' | 'list' | 'add' | 'update' | 'delete';
10
+ domain?: string;
11
+ recordId?: number;
12
+ recordType?: string;
13
+ name?: string;
14
+ data?: string;
15
+ ttl?: number;
16
+ priority?: number;
17
+ port?: number;
18
+ weight?: number;
19
+ }
20
+
21
+ export class DOManageDnsTool {
22
+ readonly id = 'doManageDns';
23
+ readonly name = 'doManageDns';
24
+ readonly displayName = 'Manage DO DNS';
25
+ readonly description = 'Manage DNS records on a DigitalOcean domain. Supports listing domains, adding domains, and full CRUD on DNS records (A, AAAA, CNAME, MX, TXT, SRV, NS, CAA). Use action "list-domains" to see all domains, "add-domain" to register a new domain, "list" to view records, "add"/"update"/"delete" to manage records.';
26
+ readonly category = 'cloud';
27
+ readonly version = '0.1.0';
28
+ readonly hasSideEffects = true;
29
+
30
+ readonly inputSchema = {
31
+ type: 'object' as const,
32
+ properties: {
33
+ action: {
34
+ type: 'string',
35
+ enum: ['list-domains', 'add-domain', 'list', 'add', 'update', 'delete'],
36
+ description: 'Action to perform on DNS',
37
+ },
38
+ domain: { type: 'string', description: 'Domain name (e.g. "example.com"). Required for all actions except "list-domains".' },
39
+ recordId: { type: 'number', description: 'Record ID (required for "update" and "delete" actions)' },
40
+ recordType: { type: 'string', description: 'DNS record type (e.g. "A", "AAAA", "CNAME", "MX", "TXT", "SRV", "NS", "CAA")' },
41
+ name: { type: 'string', description: 'Record name/hostname (e.g. "@", "www", "mail")' },
42
+ data: { type: 'string', description: 'Record data/value (e.g. IP address, CNAME target, MX server)' },
43
+ ttl: { type: 'number', description: 'Time-to-live in seconds (default: 1800)' },
44
+ priority: { type: 'number', description: 'Priority (for MX and SRV records)' },
45
+ port: { type: 'number', description: 'Port (for SRV records)' },
46
+ weight: { type: 'number', description: 'Weight (for SRV records)' },
47
+ },
48
+ required: ['action'],
49
+ };
50
+
51
+ constructor(private service: DigitalOceanService) {}
52
+
53
+ async execute(args: ManageDnsInput): Promise<{
54
+ success: boolean;
55
+ data?: DODomain | DODomain[] | DODomainRecord | DODomainRecord[] | { message: string };
56
+ error?: string;
57
+ }> {
58
+ try {
59
+ switch (args.action) {
60
+ case 'list-domains': {
61
+ const domains = await this.service.listDomains();
62
+ return { success: true, data: domains };
63
+ }
64
+
65
+ case 'add-domain': {
66
+ if (!args.domain) {
67
+ return { success: false, error: 'Domain name is required for "add-domain" action.' };
68
+ }
69
+ const domain = await this.service.addDomain(args.domain);
70
+ return { success: true, data: domain };
71
+ }
72
+
73
+ case 'list': {
74
+ if (!args.domain) {
75
+ return { success: false, error: 'Domain name is required for "list" action.' };
76
+ }
77
+ const records = await this.service.listDomainRecords(args.domain);
78
+ return { success: true, data: records };
79
+ }
80
+
81
+ case 'add': {
82
+ if (!args.domain) {
83
+ return { success: false, error: 'Domain name is required for "add" action.' };
84
+ }
85
+ if (!args.recordType || !args.name || !args.data) {
86
+ return { success: false, error: 'recordType, name, and data are required for "add" action.' };
87
+ }
88
+ const record = await this.service.createDomainRecord(args.domain, {
89
+ type: args.recordType,
90
+ name: args.name,
91
+ data: args.data,
92
+ ttl: args.ttl,
93
+ priority: args.priority,
94
+ port: args.port,
95
+ weight: args.weight,
96
+ });
97
+ return { success: true, data: record };
98
+ }
99
+
100
+ case 'update': {
101
+ if (!args.domain || args.recordId == null) {
102
+ return { success: false, error: 'Domain name and recordId are required for "update" action.' };
103
+ }
104
+ const updated = await this.service.updateDomainRecord(args.domain, args.recordId, {
105
+ type: args.recordType,
106
+ name: args.name,
107
+ data: args.data,
108
+ ttl: args.ttl,
109
+ priority: args.priority,
110
+ port: args.port,
111
+ weight: args.weight,
112
+ });
113
+ return { success: true, data: updated };
114
+ }
115
+
116
+ case 'delete': {
117
+ if (!args.domain || args.recordId == null) {
118
+ return { success: false, error: 'Domain name and recordId are required for "delete" action.' };
119
+ }
120
+ await this.service.deleteDomainRecord(args.domain, args.recordId);
121
+ return { success: true, data: { message: `Record ${args.recordId} deleted from ${args.domain}.` } };
122
+ }
123
+
124
+ default:
125
+ return { success: false, error: `Unknown action: ${args.action}` };
126
+ }
127
+ } catch (err: any) {
128
+ return { success: false, error: err.message };
129
+ }
130
+ }
131
+ }