@retrotech71/appleii-agent 1.0.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.
@@ -0,0 +1,98 @@
1
+ /*
2
+ * load-smartport-image.js - Load SmartPort hard drive image from filesystem
3
+ *
4
+ * Written by
5
+ * Shawn Bullock <shawn@agenticexpert.ai>
6
+ */
7
+
8
+ import fs from 'fs';
9
+ import path from 'path';
10
+ import { homedir } from 'os';
11
+
12
+ export const tool = {
13
+ name: "load_smartport_image",
14
+ description: "Load a SmartPort hard drive image file from the local filesystem and return as base64",
15
+ inputSchema: {
16
+ type: "object",
17
+ properties: {
18
+ path: {
19
+ type: "string",
20
+ description: "Path to SmartPort image file (supports ~ for home directory)",
21
+ },
22
+ },
23
+ required: ["path"],
24
+ },
25
+ };
26
+
27
+ export function handler(args) {
28
+ const { path: filePath } = args;
29
+
30
+ if (!filePath) {
31
+ return {
32
+ success: false,
33
+ error: "path parameter is required",
34
+ };
35
+ }
36
+
37
+ try {
38
+ // Expand ~ to home directory
39
+ let expandedPath = filePath;
40
+ if (filePath.startsWith('~/')) {
41
+ expandedPath = path.join(homedir(), filePath.slice(2));
42
+ } else if (filePath === '~') {
43
+ expandedPath = homedir();
44
+ }
45
+
46
+ // Resolve to absolute path
47
+ const absolutePath = path.resolve(expandedPath);
48
+
49
+ // Check if file exists
50
+ if (!fs.existsSync(absolutePath)) {
51
+ return {
52
+ success: false,
53
+ error: `File not found: ${absolutePath}`,
54
+ };
55
+ }
56
+
57
+ // Check if it's a file (not a directory)
58
+ const stats = fs.statSync(absolutePath);
59
+ if (!stats.isFile()) {
60
+ return {
61
+ success: false,
62
+ error: `Path is not a file: ${absolutePath}`,
63
+ };
64
+ }
65
+
66
+ // Validate SmartPort format
67
+ const supportedFormats = ['.hdv', '.po', '.2mg'];
68
+ const ext = path.extname(absolutePath).toLowerCase();
69
+ if (!supportedFormats.includes(ext)) {
70
+ return {
71
+ success: false,
72
+ error: `Unsupported SmartPort format: ${ext}. Supported formats: ${supportedFormats.join(', ')}`,
73
+ };
74
+ }
75
+
76
+ // Read file
77
+ const buffer = fs.readFileSync(absolutePath);
78
+
79
+ // Convert to base64
80
+ const base64Data = buffer.toString('base64');
81
+
82
+ // Get filename
83
+ const filename = path.basename(absolutePath);
84
+
85
+ return {
86
+ success: true,
87
+ data: base64Data,
88
+ filename: filename,
89
+ size: buffer.length,
90
+ path: absolutePath,
91
+ };
92
+ } catch (error) {
93
+ return {
94
+ success: false,
95
+ error: `Failed to load SmartPort image: ${error.message}`,
96
+ };
97
+ }
98
+ }
@@ -0,0 +1,107 @@
1
+ /*
2
+ * save-asm-file.js - Save assembly source to filesystem
3
+ *
4
+ * Written by
5
+ * Shawn Bullock <shawn@agenticexpert.ai>
6
+ */
7
+
8
+ import fs from 'fs';
9
+ import path from 'path';
10
+ import { homedir } from 'os';
11
+
12
+ export const tool = {
13
+ name: "save_asm_file",
14
+ description: "Save assembly source code to a file on the local filesystem",
15
+ inputSchema: {
16
+ type: "object",
17
+ properties: {
18
+ path: {
19
+ type: "string",
20
+ description: "Path to save file (supports ~ for home directory, .s or .asm extension recommended)",
21
+ },
22
+ content: {
23
+ type: "string",
24
+ description: "Assembly source code to save",
25
+ },
26
+ overwrite: {
27
+ type: "boolean",
28
+ description: "Allow overwriting existing file (default: false)",
29
+ default: false,
30
+ },
31
+ },
32
+ required: ["path", "content"],
33
+ },
34
+ };
35
+
36
+ export function handler(args) {
37
+ const { path: filePath, content, overwrite = false } = args;
38
+
39
+ if (!filePath) {
40
+ return {
41
+ success: false,
42
+ error: "path parameter is required",
43
+ };
44
+ }
45
+
46
+ if (content === undefined || content === null) {
47
+ return {
48
+ success: false,
49
+ error: "content parameter is required",
50
+ };
51
+ }
52
+
53
+ try {
54
+ // Expand ~ to home directory
55
+ let expandedPath = filePath;
56
+ if (filePath.startsWith('~/')) {
57
+ expandedPath = path.join(homedir(), filePath.slice(2));
58
+ } else if (filePath === '~') {
59
+ return {
60
+ success: false,
61
+ error: "Cannot save to home directory root, please specify a filename",
62
+ };
63
+ }
64
+
65
+ // Resolve to absolute path
66
+ const absolutePath = path.resolve(expandedPath);
67
+
68
+ // Ensure parent directory exists
69
+ const dir = path.dirname(absolutePath);
70
+ if (!fs.existsSync(dir)) {
71
+ return {
72
+ success: false,
73
+ error: `Directory does not exist: ${dir}`,
74
+ };
75
+ }
76
+
77
+ // Check if file already exists
78
+ if (fs.existsSync(absolutePath) && !overwrite) {
79
+ return {
80
+ success: false,
81
+ error: `File already exists: ${absolutePath}. Use overwrite: true to replace it.`,
82
+ exists: true,
83
+ };
84
+ }
85
+
86
+ // Write file
87
+ fs.writeFileSync(absolutePath, content, 'utf8');
88
+
89
+ // Get file stats
90
+ const stats = fs.statSync(absolutePath);
91
+ const filename = path.basename(absolutePath);
92
+
93
+ return {
94
+ success: true,
95
+ filename: filename,
96
+ path: absolutePath,
97
+ size: stats.size,
98
+ lines: content.split('\n').length,
99
+ message: `Assembly source saved to ${filename}`,
100
+ };
101
+ } catch (error) {
102
+ return {
103
+ success: false,
104
+ error: `Failed to save file: ${error.message}`,
105
+ };
106
+ }
107
+ }
@@ -0,0 +1,107 @@
1
+ /*
2
+ * save-basic-file.js - Save BASIC program to filesystem
3
+ *
4
+ * Written by
5
+ * Shawn Bullock <shawn@agenticexpert.ai>
6
+ */
7
+
8
+ import fs from 'fs';
9
+ import path from 'path';
10
+ import { homedir } from 'os';
11
+
12
+ export const tool = {
13
+ name: "save_basic_file",
14
+ description: "Save BASIC program text to a file on the local filesystem",
15
+ inputSchema: {
16
+ type: "object",
17
+ properties: {
18
+ path: {
19
+ type: "string",
20
+ description: "Path to save file (supports ~ for home directory, .bas extension recommended)",
21
+ },
22
+ content: {
23
+ type: "string",
24
+ description: "BASIC program text to save",
25
+ },
26
+ overwrite: {
27
+ type: "boolean",
28
+ description: "Allow overwriting existing file (default: false)",
29
+ default: false,
30
+ },
31
+ },
32
+ required: ["path", "content"],
33
+ },
34
+ };
35
+
36
+ export function handler(args) {
37
+ const { path: filePath, content, overwrite = false } = args;
38
+
39
+ if (!filePath) {
40
+ return {
41
+ success: false,
42
+ error: "path parameter is required",
43
+ };
44
+ }
45
+
46
+ if (content === undefined || content === null) {
47
+ return {
48
+ success: false,
49
+ error: "content parameter is required",
50
+ };
51
+ }
52
+
53
+ try {
54
+ // Expand ~ to home directory
55
+ let expandedPath = filePath;
56
+ if (filePath.startsWith('~/')) {
57
+ expandedPath = path.join(homedir(), filePath.slice(2));
58
+ } else if (filePath === '~') {
59
+ return {
60
+ success: false,
61
+ error: "Cannot save to home directory root, please specify a filename",
62
+ };
63
+ }
64
+
65
+ // Resolve to absolute path
66
+ const absolutePath = path.resolve(expandedPath);
67
+
68
+ // Ensure parent directory exists
69
+ const dir = path.dirname(absolutePath);
70
+ if (!fs.existsSync(dir)) {
71
+ return {
72
+ success: false,
73
+ error: `Directory does not exist: ${dir}`,
74
+ };
75
+ }
76
+
77
+ // Check if file already exists
78
+ if (fs.existsSync(absolutePath) && !overwrite) {
79
+ return {
80
+ success: false,
81
+ error: `File already exists: ${absolutePath}. Use overwrite: true to replace it.`,
82
+ exists: true,
83
+ };
84
+ }
85
+
86
+ // Write file
87
+ fs.writeFileSync(absolutePath, content, 'utf8');
88
+
89
+ // Get file stats
90
+ const stats = fs.statSync(absolutePath);
91
+ const filename = path.basename(absolutePath);
92
+
93
+ return {
94
+ success: true,
95
+ filename: filename,
96
+ path: absolutePath,
97
+ size: stats.size,
98
+ lines: content.split('\n').length,
99
+ message: `BASIC program saved to ${filename}`,
100
+ };
101
+ } catch (error) {
102
+ return {
103
+ success: false,
104
+ error: `Failed to save file: ${error.message}`,
105
+ };
106
+ }
107
+ }
@@ -0,0 +1,85 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import os from 'os';
4
+
5
+ export const tool = {
6
+ name: "save_disk_file",
7
+ description: "Save disk file content to the local filesystem. Content should be base64 encoded binary data.",
8
+ inputSchema: {
9
+ type: "object",
10
+ properties: {
11
+ path: {
12
+ type: "string",
13
+ description: "Path to save the file (supports ~ for home directory)"
14
+ },
15
+ contentBase64: {
16
+ type: "string",
17
+ description: "Base64 encoded file content"
18
+ },
19
+ overwrite: {
20
+ type: "boolean",
21
+ description: "Allow overwriting existing files (default: false)",
22
+ default: false
23
+ }
24
+ },
25
+ required: ["path", "contentBase64"]
26
+ }
27
+ };
28
+
29
+ export function handler(args) {
30
+ const { path: filePath, contentBase64, overwrite = false } = args;
31
+
32
+ if (!filePath) {
33
+ return {
34
+ success: false,
35
+ error: "path parameter is required"
36
+ };
37
+ }
38
+
39
+ if (!contentBase64) {
40
+ return {
41
+ success: false,
42
+ error: "contentBase64 parameter is required"
43
+ };
44
+ }
45
+
46
+ try {
47
+ // Expand ~ to home directory
48
+ let expandedPath = filePath;
49
+ if (filePath.startsWith('~')) {
50
+ expandedPath = path.join(os.homedir(), filePath.slice(1));
51
+ }
52
+
53
+ // Check if file exists and overwrite is false
54
+ if (!overwrite && fs.existsSync(expandedPath)) {
55
+ return {
56
+ success: false,
57
+ error: `File already exists: ${expandedPath}. Set overwrite: true to replace it.`
58
+ };
59
+ }
60
+
61
+ // Decode base64 content
62
+ const buffer = Buffer.from(contentBase64, 'base64');
63
+
64
+ // Ensure directory exists
65
+ const dir = path.dirname(expandedPath);
66
+ if (!fs.existsSync(dir)) {
67
+ fs.mkdirSync(dir, { recursive: true });
68
+ }
69
+
70
+ // Write file
71
+ fs.writeFileSync(expandedPath, buffer);
72
+
73
+ return {
74
+ success: true,
75
+ path: expandedPath,
76
+ size: buffer.length,
77
+ message: `File saved successfully: ${expandedPath} (${buffer.length} bytes)`
78
+ };
79
+ } catch (error) {
80
+ return {
81
+ success: false,
82
+ error: error.message
83
+ };
84
+ }
85
+ }
@@ -0,0 +1,52 @@
1
+ /*
2
+ * server-control.js - HTTP server control tool
3
+ *
4
+ * Written by
5
+ * Shawn Bullock <shawn@agenticexpert.ai>
6
+ */
7
+
8
+ export const tool = {
9
+ name: "server_control",
10
+ description: "Control the AG-UI HTTP/HTTPS server (start, stop, restart)",
11
+ inputSchema: {
12
+ type: "object",
13
+ properties: {
14
+ action: {
15
+ type: "string",
16
+ enum: ["start", "stop", "restart", "status"],
17
+ description: "Action to perform",
18
+ },
19
+ },
20
+ required: ["action"],
21
+ },
22
+ };
23
+
24
+ export async function handler(args, httpServer) {
25
+ const { action } = args;
26
+
27
+ switch (action) {
28
+ case "start":
29
+ if (httpServer.getStatus().running) {
30
+ return { status: "already_running", ...httpServer.getStatus() };
31
+ }
32
+ await httpServer.start();
33
+ return { status: "started", ...httpServer.getStatus() };
34
+
35
+ case "stop":
36
+ if (!httpServer.getStatus().running) {
37
+ return { status: "already_stopped", ...httpServer.getStatus() };
38
+ }
39
+ await httpServer.stop();
40
+ return { status: "stopped", ...httpServer.getStatus() };
41
+
42
+ case "restart":
43
+ await httpServer.restart();
44
+ return { status: "restarted", ...httpServer.getStatus() };
45
+
46
+ case "status":
47
+ return httpServer.getStatus();
48
+
49
+ default:
50
+ throw new Error(`Unknown action: ${action}`);
51
+ }
52
+ }
@@ -0,0 +1,33 @@
1
+ /*
2
+ * set-debug.js - Debug mode control tool
3
+ *
4
+ * Written by
5
+ * Shawn Bullock <shawn@agenticexpert.ai>
6
+ */
7
+
8
+ export const tool = {
9
+ name: "set_debug",
10
+ description: "Enable or disable debug logging for the HTTP server",
11
+ inputSchema: {
12
+ type: "object",
13
+ properties: {
14
+ enabled: {
15
+ type: "boolean",
16
+ description: "True to enable debug logs, false to disable",
17
+ },
18
+ },
19
+ required: ["enabled"],
20
+ },
21
+ };
22
+
23
+ export async function handler(args, httpServer) {
24
+ const { enabled } = args;
25
+
26
+ httpServer.setDebug(enabled);
27
+
28
+ return {
29
+ status: "updated",
30
+ debug: enabled,
31
+ current: httpServer.getStatus(),
32
+ };
33
+ }
@@ -0,0 +1,34 @@
1
+ /*
2
+ * set-https.js - HTTPS mode control tool
3
+ *
4
+ * Written by
5
+ * Shawn Bullock <shawn@agenticexpert.ai>
6
+ */
7
+
8
+ export const tool = {
9
+ name: "set_https",
10
+ description: "Enable or disable HTTPS mode for the server",
11
+ inputSchema: {
12
+ type: "object",
13
+ properties: {
14
+ enabled: {
15
+ type: "boolean",
16
+ description: "True for HTTPS, false for HTTP",
17
+ },
18
+ },
19
+ required: ["enabled"],
20
+ },
21
+ };
22
+
23
+ export async function handler(args, httpServer) {
24
+ const { enabled } = args;
25
+ const oldStatus = httpServer.getStatus();
26
+
27
+ await httpServer.setHttps(enabled);
28
+
29
+ return {
30
+ status: "updated",
31
+ previous: oldStatus,
32
+ current: httpServer.getStatus(),
33
+ };
34
+ }
@@ -0,0 +1,45 @@
1
+ /*
2
+ * show-window.js - Show a window in the emulator
3
+ *
4
+ * Written by
5
+ * Shawn Bullock <shawn@agenticexpert.ai>
6
+ */
7
+
8
+ export const tool = {
9
+ name: "showWindow",
10
+ description: "Show and bring to front a window in the Apple //e emulator (e.g., disk-drives, basic-program)",
11
+ inputSchema: {
12
+ type: "object",
13
+ properties: {
14
+ windowId: {
15
+ type: "string",
16
+ description: "Window ID (e.g., 'disk-drives', 'basic-program', 'cpu-debugger')",
17
+ },
18
+ },
19
+ required: ["windowId"],
20
+ },
21
+ };
22
+
23
+ export async function handler(args, httpServer) {
24
+ const toolCallId = `tc_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
25
+
26
+ await httpServer.sendEvent({
27
+ type: "TOOL_CALL_START",
28
+ tool_call_id: toolCallId,
29
+ tool_call_name: "showWindow",
30
+ });
31
+
32
+ await httpServer.sendEvent({
33
+ type: "TOOL_CALL_ARGS",
34
+ tool_call_id: toolCallId,
35
+ delta: JSON.stringify(args),
36
+ });
37
+
38
+ await httpServer.sendEvent({
39
+ type: "TOOL_CALL_END",
40
+ tool_call_id: toolCallId,
41
+ });
42
+
43
+ const result = await httpServer.waitForToolResult(toolCallId, 10000);
44
+ return result;
45
+ }