@1medium/cli 1.7.0 → 1.9.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.
- package/package.json +1 -1
- package/src/api.js +144 -0
- package/src/index.js +261 -0
- package/src/mcp-server.js +4 -4
package/package.json
CHANGED
package/src/api.js
CHANGED
|
@@ -89,6 +89,54 @@ async function request(method, path, body = null, params = null) {
|
|
|
89
89
|
return data;
|
|
90
90
|
}
|
|
91
91
|
|
|
92
|
+
/**
|
|
93
|
+
* Make an authenticated API request to non-agent routes (e.g. /scripts, /script-events)
|
|
94
|
+
*/
|
|
95
|
+
async function requestDirect(method, path, body = null, params = null) {
|
|
96
|
+
const baseUrl = getApiUrl();
|
|
97
|
+
const token = getToken();
|
|
98
|
+
|
|
99
|
+
let url = `${baseUrl}${path}`;
|
|
100
|
+
if (params) {
|
|
101
|
+
const searchParams = new URLSearchParams();
|
|
102
|
+
for (const [key, value] of Object.entries(params)) {
|
|
103
|
+
if (value !== undefined && value !== null) {
|
|
104
|
+
searchParams.append(key, value);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
const queryString = searchParams.toString();
|
|
108
|
+
if (queryString) {
|
|
109
|
+
url += `?${queryString}`;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const options = {
|
|
114
|
+
method,
|
|
115
|
+
headers: {
|
|
116
|
+
Authorization: `Bearer ${token}`,
|
|
117
|
+
"Content-Type": "application/json",
|
|
118
|
+
"User-Agent": "1m-cli/1.0.0",
|
|
119
|
+
},
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
if (body && (method === "POST" || method === "PATCH" || method === "PUT")) {
|
|
123
|
+
options.body = JSON.stringify(body);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const response = await fetch(url, options);
|
|
127
|
+
const data = await response.json();
|
|
128
|
+
|
|
129
|
+
if (!response.ok) {
|
|
130
|
+
const message = data.message || data.error || "API request failed";
|
|
131
|
+
const error = new Error(message);
|
|
132
|
+
error.statusCode = response.status;
|
|
133
|
+
error.details = data.details;
|
|
134
|
+
throw error;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
return data;
|
|
138
|
+
}
|
|
139
|
+
|
|
92
140
|
/**
|
|
93
141
|
* Token introspection
|
|
94
142
|
*/
|
|
@@ -208,6 +256,91 @@ async function deleteProject(id) {
|
|
|
208
256
|
return request("DELETE", `/projects/${id}`);
|
|
209
257
|
}
|
|
210
258
|
|
|
259
|
+
// ============================================================================
|
|
260
|
+
// Script API
|
|
261
|
+
// ============================================================================
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* List scripts
|
|
265
|
+
*/
|
|
266
|
+
async function listScripts(params = {}) {
|
|
267
|
+
return requestDirect("GET", "/scripts", null, params);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* Get a single script
|
|
272
|
+
*/
|
|
273
|
+
async function getScript(id) {
|
|
274
|
+
return requestDirect("GET", `/scripts/${id}`);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Push (create/update) a script
|
|
279
|
+
*/
|
|
280
|
+
async function pushScript(payload) {
|
|
281
|
+
return requestDirect("POST", "/scripts/push", payload);
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* Deprecate a script
|
|
286
|
+
*/
|
|
287
|
+
async function deprecateScript(id) {
|
|
288
|
+
return requestDirect("POST", `/scripts/${id}/deprecate`);
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
// ============================================================================
|
|
292
|
+
// Script Event API
|
|
293
|
+
// ============================================================================
|
|
294
|
+
|
|
295
|
+
/**
|
|
296
|
+
* List script events
|
|
297
|
+
*/
|
|
298
|
+
async function listScriptEvents(params = {}) {
|
|
299
|
+
return requestDirect("GET", "/script-events", null, params);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/**
|
|
303
|
+
* Get a single script event
|
|
304
|
+
*/
|
|
305
|
+
async function getScriptEvent(id) {
|
|
306
|
+
return requestDirect("GET", `/script-events/${id}`);
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* Create a script event
|
|
311
|
+
*/
|
|
312
|
+
async function createScriptEvent(payload) {
|
|
313
|
+
return requestDirect("POST", "/script-events", payload);
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
/**
|
|
317
|
+
* Update a script event
|
|
318
|
+
*/
|
|
319
|
+
async function updateScriptEvent(id, payload) {
|
|
320
|
+
return requestDirect("PUT", `/script-events/${id}`, payload);
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
/**
|
|
324
|
+
* Delete a script event
|
|
325
|
+
*/
|
|
326
|
+
async function deleteScriptEvent(id) {
|
|
327
|
+
return requestDirect("DELETE", `/script-events/${id}`);
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
/**
|
|
331
|
+
* Pause a script event
|
|
332
|
+
*/
|
|
333
|
+
async function pauseScriptEvent(id) {
|
|
334
|
+
return requestDirect("POST", `/script-events/${id}/pause`);
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
/**
|
|
338
|
+
* Resume a script event
|
|
339
|
+
*/
|
|
340
|
+
async function resumeScriptEvent(id) {
|
|
341
|
+
return requestDirect("POST", `/script-events/${id}/resume`);
|
|
342
|
+
}
|
|
343
|
+
|
|
211
344
|
module.exports = {
|
|
212
345
|
whoami,
|
|
213
346
|
createTask,
|
|
@@ -226,4 +359,15 @@ module.exports = {
|
|
|
226
359
|
createProject,
|
|
227
360
|
updateProject,
|
|
228
361
|
deleteProject,
|
|
362
|
+
listScripts,
|
|
363
|
+
getScript,
|
|
364
|
+
pushScript,
|
|
365
|
+
deprecateScript,
|
|
366
|
+
listScriptEvents,
|
|
367
|
+
getScriptEvent,
|
|
368
|
+
createScriptEvent,
|
|
369
|
+
updateScriptEvent,
|
|
370
|
+
deleteScriptEvent,
|
|
371
|
+
pauseScriptEvent,
|
|
372
|
+
resumeScriptEvent,
|
|
229
373
|
};
|
package/src/index.js
CHANGED
|
@@ -714,6 +714,267 @@ program
|
|
|
714
714
|
}
|
|
715
715
|
});
|
|
716
716
|
|
|
717
|
+
// ============================================================================
|
|
718
|
+
// Script Commands
|
|
719
|
+
// ============================================================================
|
|
720
|
+
|
|
721
|
+
const scriptCmd = program.command("script").description("Manage scripts");
|
|
722
|
+
|
|
723
|
+
scriptCmd
|
|
724
|
+
.command("push <file>")
|
|
725
|
+
.description("Push a script from a local file")
|
|
726
|
+
.option("-n, --name <name>", "Script name (defaults to filename)")
|
|
727
|
+
.option("--trigger <trigger>", "Trigger type: onCreate, onUpdate, onTag, schedule", "schedule")
|
|
728
|
+
.option("-j, --json", "Output as JSON")
|
|
729
|
+
.action(async (file, options) => {
|
|
730
|
+
try {
|
|
731
|
+
const fs = require("fs");
|
|
732
|
+
const path = require("path");
|
|
733
|
+
|
|
734
|
+
if (!fs.existsSync(file)) {
|
|
735
|
+
console.error(chalk.red(`Error: File not found: ${file}`));
|
|
736
|
+
process.exit(1);
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
const code = fs.readFileSync(file, "utf-8");
|
|
740
|
+
const name = options.name || path.basename(file, path.extname(file));
|
|
741
|
+
|
|
742
|
+
// Extract metadata from header comments
|
|
743
|
+
const metadata = {};
|
|
744
|
+
const metaRegex = /\/\/\s*@(\w+)\s+(.*)/g;
|
|
745
|
+
let match;
|
|
746
|
+
while ((match = metaRegex.exec(code)) !== null) {
|
|
747
|
+
metadata[match[1]] = match[2].trim();
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
const payload = {
|
|
751
|
+
name,
|
|
752
|
+
code,
|
|
753
|
+
trigger: metadata.trigger || options.trigger,
|
|
754
|
+
};
|
|
755
|
+
|
|
756
|
+
const data = await api.pushScript(payload);
|
|
757
|
+
|
|
758
|
+
if (options.json) {
|
|
759
|
+
console.log(JSON.stringify(data, null, 2));
|
|
760
|
+
} else {
|
|
761
|
+
console.log(chalk.green("Script pushed:"));
|
|
762
|
+
console.log(` ID: ${data.script?.id || data.id}`);
|
|
763
|
+
console.log(` Name: ${name}`);
|
|
764
|
+
console.log(` Version: ${data.script?.version || data.version || 1}`);
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
// Auto-create schedule if metadata includes startDateTime
|
|
768
|
+
if (metadata.startDateTime) {
|
|
769
|
+
const eventPayload = {
|
|
770
|
+
ScriptId: data.script?.id || data.id,
|
|
771
|
+
title: metadata.title || name,
|
|
772
|
+
startDateTime: metadata.startDateTime,
|
|
773
|
+
timezone: metadata.tz || metadata.timezone || "UTC",
|
|
774
|
+
};
|
|
775
|
+
if (metadata.rrule) eventPayload.rrule = metadata.rrule;
|
|
776
|
+
if (metadata.endDateTime) eventPayload.endDateTime = metadata.endDateTime;
|
|
777
|
+
|
|
778
|
+
const eventData = await api.createScriptEvent(eventPayload);
|
|
779
|
+
console.log(chalk.green("\nSchedule created:"));
|
|
780
|
+
console.log(` Event ID: ${eventData.scriptEvent?.id || eventData.id}`);
|
|
781
|
+
console.log(` Starts: ${eventPayload.startDateTime}`);
|
|
782
|
+
if (eventPayload.rrule) {
|
|
783
|
+
console.log(` Recurs: ${eventPayload.rrule}`);
|
|
784
|
+
}
|
|
785
|
+
}
|
|
786
|
+
} catch (error) {
|
|
787
|
+
console.error(chalk.red(`Error: ${error.message}`));
|
|
788
|
+
if (error.details) {
|
|
789
|
+
error.details.forEach((d) => console.error(chalk.red(` - ${d}`)));
|
|
790
|
+
}
|
|
791
|
+
process.exit(1);
|
|
792
|
+
}
|
|
793
|
+
});
|
|
794
|
+
|
|
795
|
+
scriptCmd
|
|
796
|
+
.command("list")
|
|
797
|
+
.description("List your scripts")
|
|
798
|
+
.option("-j, --json", "Output as JSON")
|
|
799
|
+
.action(async (options) => {
|
|
800
|
+
try {
|
|
801
|
+
const data = await api.listScripts();
|
|
802
|
+
const scripts = data.scripts || data;
|
|
803
|
+
|
|
804
|
+
if (options.json) {
|
|
805
|
+
console.log(JSON.stringify(data, null, 2));
|
|
806
|
+
} else {
|
|
807
|
+
console.log(chalk.bold("\nScripts:\n"));
|
|
808
|
+
if (!scripts.length) {
|
|
809
|
+
console.log(" No scripts found.");
|
|
810
|
+
} else {
|
|
811
|
+
for (const script of scripts) {
|
|
812
|
+
const statusColor = script.status === "active" ? chalk.green : chalk.gray;
|
|
813
|
+
console.log(` ${statusColor(script.status)} ${script.name} (v${script.version || 1})`);
|
|
814
|
+
console.log(chalk.gray(` ID: ${script.id} Trigger: ${script.trigger}`));
|
|
815
|
+
}
|
|
816
|
+
}
|
|
817
|
+
console.log("");
|
|
818
|
+
}
|
|
819
|
+
} catch (error) {
|
|
820
|
+
console.error(chalk.red(`Error: ${error.message}`));
|
|
821
|
+
process.exit(1);
|
|
822
|
+
}
|
|
823
|
+
});
|
|
824
|
+
|
|
825
|
+
scriptCmd
|
|
826
|
+
.command("delete <id>")
|
|
827
|
+
.description("Deprecate a script (soft delete)")
|
|
828
|
+
.option("-j, --json", "Output as JSON")
|
|
829
|
+
.action(async (id, options) => {
|
|
830
|
+
try {
|
|
831
|
+
const data = await api.deprecateScript(id);
|
|
832
|
+
|
|
833
|
+
if (options.json) {
|
|
834
|
+
console.log(JSON.stringify(data, null, 2));
|
|
835
|
+
} else {
|
|
836
|
+
console.log(chalk.green(`Script deprecated: ${id}`));
|
|
837
|
+
}
|
|
838
|
+
} catch (error) {
|
|
839
|
+
console.error(chalk.red(`Error: ${error.message}`));
|
|
840
|
+
process.exit(1);
|
|
841
|
+
}
|
|
842
|
+
});
|
|
843
|
+
|
|
844
|
+
scriptCmd
|
|
845
|
+
.command("schedule <script-id>")
|
|
846
|
+
.description("Schedule a script as a calendar event")
|
|
847
|
+
.requiredOption("--start <datetime>", "Start date/time (ISO 8601)")
|
|
848
|
+
.option("--end <datetime>", "End date/time (ISO 8601)")
|
|
849
|
+
.option("--rrule <rrule>", "Recurrence rule (RFC 5545 RRULE)")
|
|
850
|
+
.option("--tz <timezone>", "Timezone (e.g., America/New_York)", "UTC")
|
|
851
|
+
.option("-t, --title <title>", "Event title")
|
|
852
|
+
.option("-j, --json", "Output as JSON")
|
|
853
|
+
.action(async (scriptId, options) => {
|
|
854
|
+
try {
|
|
855
|
+
const payload = {
|
|
856
|
+
ScriptId: scriptId,
|
|
857
|
+
title: options.title || `Script ${scriptId}`,
|
|
858
|
+
startDateTime: options.start,
|
|
859
|
+
timezone: options.tz,
|
|
860
|
+
};
|
|
861
|
+
if (options.end) payload.endDateTime = options.end;
|
|
862
|
+
if (options.rrule) payload.rrule = options.rrule;
|
|
863
|
+
|
|
864
|
+
const data = await api.createScriptEvent(payload);
|
|
865
|
+
const event = data.scriptEvent || data;
|
|
866
|
+
|
|
867
|
+
if (options.json) {
|
|
868
|
+
console.log(JSON.stringify(data, null, 2));
|
|
869
|
+
} else {
|
|
870
|
+
console.log(chalk.green("Script scheduled:"));
|
|
871
|
+
console.log(` Event ID: ${event.id}`);
|
|
872
|
+
console.log(` Title: ${event.title}`);
|
|
873
|
+
console.log(` Starts: ${event.startDateTime}`);
|
|
874
|
+
console.log(` Timezone: ${event.timezone}`);
|
|
875
|
+
if (event.rrule) {
|
|
876
|
+
console.log(` Recurs: ${event.rrule}`);
|
|
877
|
+
}
|
|
878
|
+
if (event.nextRunAt) {
|
|
879
|
+
console.log(` Next run: ${event.nextRunAt}`);
|
|
880
|
+
}
|
|
881
|
+
}
|
|
882
|
+
} catch (error) {
|
|
883
|
+
console.error(chalk.red(`Error: ${error.message}`));
|
|
884
|
+
if (error.details) {
|
|
885
|
+
error.details.forEach((d) => console.error(chalk.red(` - ${d}`)));
|
|
886
|
+
}
|
|
887
|
+
process.exit(1);
|
|
888
|
+
}
|
|
889
|
+
});
|
|
890
|
+
|
|
891
|
+
scriptCmd
|
|
892
|
+
.command("events")
|
|
893
|
+
.description("List scheduled script events")
|
|
894
|
+
.option("--start <date>", "Filter by start date (ISO 8601)")
|
|
895
|
+
.option("--end <date>", "Filter by end date (ISO 8601)")
|
|
896
|
+
.option("-j, --json", "Output as JSON")
|
|
897
|
+
.action(async (options) => {
|
|
898
|
+
try {
|
|
899
|
+
const params = {};
|
|
900
|
+
if (options.start) params.start = options.start;
|
|
901
|
+
if (options.end) params.end = options.end;
|
|
902
|
+
|
|
903
|
+
const data = await api.listScriptEvents(params);
|
|
904
|
+
const events = data.scriptEvents || data;
|
|
905
|
+
|
|
906
|
+
if (options.json) {
|
|
907
|
+
console.log(JSON.stringify(data, null, 2));
|
|
908
|
+
} else {
|
|
909
|
+
console.log(chalk.bold("\nScheduled Script Events:\n"));
|
|
910
|
+
if (!events.length) {
|
|
911
|
+
console.log(" No scheduled events found.");
|
|
912
|
+
} else {
|
|
913
|
+
for (const event of events) {
|
|
914
|
+
const statusColor =
|
|
915
|
+
event.status === "active" ? chalk.green :
|
|
916
|
+
event.status === "paused" ? chalk.yellow :
|
|
917
|
+
chalk.gray;
|
|
918
|
+
console.log(` ${statusColor(event.status)} ${event.title}`);
|
|
919
|
+
console.log(chalk.gray(` ID: ${event.id}`));
|
|
920
|
+
console.log(chalk.gray(` Start: ${event.startDateTime} TZ: ${event.timezone}`));
|
|
921
|
+
if (event.rrule) {
|
|
922
|
+
console.log(chalk.gray(` Recurs: ${event.rrule}`));
|
|
923
|
+
}
|
|
924
|
+
if (event.nextRunAt) {
|
|
925
|
+
console.log(chalk.gray(` Next run: ${event.nextRunAt}`));
|
|
926
|
+
}
|
|
927
|
+
if (event.Script) {
|
|
928
|
+
console.log(chalk.gray(` Script: ${event.Script.name} (${event.Script.id})`));
|
|
929
|
+
}
|
|
930
|
+
}
|
|
931
|
+
}
|
|
932
|
+
console.log("");
|
|
933
|
+
}
|
|
934
|
+
} catch (error) {
|
|
935
|
+
console.error(chalk.red(`Error: ${error.message}`));
|
|
936
|
+
process.exit(1);
|
|
937
|
+
}
|
|
938
|
+
});
|
|
939
|
+
|
|
940
|
+
scriptCmd
|
|
941
|
+
.command("pause <event-id>")
|
|
942
|
+
.description("Pause a scheduled script event")
|
|
943
|
+
.option("-j, --json", "Output as JSON")
|
|
944
|
+
.action(async (eventId, options) => {
|
|
945
|
+
try {
|
|
946
|
+
const data = await api.pauseScriptEvent(eventId);
|
|
947
|
+
|
|
948
|
+
if (options.json) {
|
|
949
|
+
console.log(JSON.stringify(data, null, 2));
|
|
950
|
+
} else {
|
|
951
|
+
console.log(chalk.green(`Script event paused: ${eventId}`));
|
|
952
|
+
}
|
|
953
|
+
} catch (error) {
|
|
954
|
+
console.error(chalk.red(`Error: ${error.message}`));
|
|
955
|
+
process.exit(1);
|
|
956
|
+
}
|
|
957
|
+
});
|
|
958
|
+
|
|
959
|
+
scriptCmd
|
|
960
|
+
.command("resume <event-id>")
|
|
961
|
+
.description("Resume a paused script event")
|
|
962
|
+
.option("-j, --json", "Output as JSON")
|
|
963
|
+
.action(async (eventId, options) => {
|
|
964
|
+
try {
|
|
965
|
+
const data = await api.resumeScriptEvent(eventId);
|
|
966
|
+
|
|
967
|
+
if (options.json) {
|
|
968
|
+
console.log(JSON.stringify(data, null, 2));
|
|
969
|
+
} else {
|
|
970
|
+
console.log(chalk.green(`Script event resumed: ${eventId}`));
|
|
971
|
+
}
|
|
972
|
+
} catch (error) {
|
|
973
|
+
console.error(chalk.red(`Error: ${error.message}`));
|
|
974
|
+
process.exit(1);
|
|
975
|
+
}
|
|
976
|
+
});
|
|
977
|
+
|
|
717
978
|
// ============================================================================
|
|
718
979
|
// Config Commands
|
|
719
980
|
// ============================================================================
|
package/src/mcp-server.js
CHANGED
|
@@ -152,7 +152,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
152
152
|
properties: {
|
|
153
153
|
id: {
|
|
154
154
|
type: "string",
|
|
155
|
-
description: "Task ID (
|
|
155
|
+
description: "Task ID (e.g. VOBEX-6hd, or UUID)",
|
|
156
156
|
},
|
|
157
157
|
},
|
|
158
158
|
required: ["id"],
|
|
@@ -166,7 +166,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
166
166
|
properties: {
|
|
167
167
|
id: {
|
|
168
168
|
type: "string",
|
|
169
|
-
description: "Task ID
|
|
169
|
+
description: "Task ID (e.g. VOBEX-6hd, or UUID)",
|
|
170
170
|
},
|
|
171
171
|
title: {
|
|
172
172
|
type: "string",
|
|
@@ -197,7 +197,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
197
197
|
properties: {
|
|
198
198
|
id: {
|
|
199
199
|
type: "string",
|
|
200
|
-
description: "Task ID
|
|
200
|
+
description: "Task ID (e.g. VOBEX-6hd, or UUID)",
|
|
201
201
|
},
|
|
202
202
|
summary: {
|
|
203
203
|
type: "string",
|
|
@@ -215,7 +215,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
215
215
|
properties: {
|
|
216
216
|
id: {
|
|
217
217
|
type: "string",
|
|
218
|
-
description: "Task ID
|
|
218
|
+
description: "Task ID (e.g. VOBEX-6hd, or UUID)",
|
|
219
219
|
},
|
|
220
220
|
message: {
|
|
221
221
|
type: "string",
|