@serviceme/devtools-core 0.1.6 → 0.1.8
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/dist/index.d.mts +127 -75
- package/dist/index.d.ts +127 -75
- package/dist/index.js +214 -137
- package/dist/index.mjs +209 -139
- package/package.json +4 -2
package/dist/index.js
CHANGED
|
@@ -72,6 +72,7 @@ __export(index_exports, {
|
|
|
72
72
|
module.exports = __toCommonJS(index_exports);
|
|
73
73
|
|
|
74
74
|
// src/agents/AgentCatalogClient.ts
|
|
75
|
+
var import_devtools_protocol = require("@serviceme/devtools-protocol");
|
|
75
76
|
var AgentCatalogClient = class {
|
|
76
77
|
constructor(options = {}) {
|
|
77
78
|
this.fetchImpl = options.fetchImpl ?? fetch;
|
|
@@ -79,10 +80,10 @@ var AgentCatalogClient = class {
|
|
|
79
80
|
}
|
|
80
81
|
async getCatalog() {
|
|
81
82
|
if (!this.baseUrl) {
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
83
|
+
throw (0, import_devtools_protocol.createServicemeError)(
|
|
84
|
+
"workspace_not_found",
|
|
85
|
+
"Agent catalog baseUrl is not configured."
|
|
86
|
+
);
|
|
86
87
|
}
|
|
87
88
|
const response = await this.fetchImpl(
|
|
88
89
|
`${this.baseUrl}/api/v1/marketplace/agents`
|
|
@@ -96,6 +97,30 @@ var AgentCatalogClient = class {
|
|
|
96
97
|
fetchedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
97
98
|
};
|
|
98
99
|
}
|
|
100
|
+
async downloadAgent(remoteId) {
|
|
101
|
+
if (!this.baseUrl) {
|
|
102
|
+
throw (0, import_devtools_protocol.createServicemeError)(
|
|
103
|
+
"workspace_not_found",
|
|
104
|
+
"Agent catalog baseUrl is not configured."
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
const response = await this.fetchImpl(
|
|
108
|
+
`${this.baseUrl}/api/v1/marketplace/agents/download/${remoteId}`
|
|
109
|
+
);
|
|
110
|
+
if (!response.ok) {
|
|
111
|
+
if (response.status === 404) {
|
|
112
|
+
throw (0, import_devtools_protocol.createServicemeError)(
|
|
113
|
+
"not_found",
|
|
114
|
+
`Agent '${remoteId}' not found`
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
throw new Error(
|
|
118
|
+
`Failed to download agent ${remoteId}: ${response.status}`
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
const payload = await response.json();
|
|
122
|
+
return payload.data?.files ?? [];
|
|
123
|
+
}
|
|
99
124
|
};
|
|
100
125
|
|
|
101
126
|
// src/permissions/agent-permissions.ts
|
|
@@ -353,7 +378,7 @@ var AgentStore = class {
|
|
|
353
378
|
};
|
|
354
379
|
|
|
355
380
|
// src/copilot/doctor.ts
|
|
356
|
-
var
|
|
381
|
+
var import_devtools_protocol2 = require("@serviceme/devtools-protocol");
|
|
357
382
|
|
|
358
383
|
// src/process/runCommand.ts
|
|
359
384
|
var import_node_child_process = require("child_process");
|
|
@@ -497,20 +522,20 @@ async function copilotDoctor() {
|
|
|
497
522
|
return { installed: true, version, authenticated };
|
|
498
523
|
}
|
|
499
524
|
function createCopilotNotInstalledError() {
|
|
500
|
-
return (0,
|
|
501
|
-
|
|
525
|
+
return (0, import_devtools_protocol2.createServicemeError)(
|
|
526
|
+
import_devtools_protocol2.COPILOT_ERROR_CODES.NOT_INSTALLED,
|
|
502
527
|
"GitHub Copilot CLI is not installed. Visit https://docs.github.com/en/copilot/using-github-copilot/using-github-copilot-in-the-command-line to install."
|
|
503
528
|
);
|
|
504
529
|
}
|
|
505
530
|
function createCopilotAuthRequiredError() {
|
|
506
|
-
return (0,
|
|
507
|
-
|
|
531
|
+
return (0, import_devtools_protocol2.createServicemeError)(
|
|
532
|
+
import_devtools_protocol2.COPILOT_ERROR_CODES.AUTH_REQUIRED,
|
|
508
533
|
"GitHub Copilot CLI requires authentication. Run `copilot auth login` to sign in."
|
|
509
534
|
);
|
|
510
535
|
}
|
|
511
536
|
|
|
512
537
|
// src/copilot/prompt.ts
|
|
513
|
-
var
|
|
538
|
+
var import_devtools_protocol3 = require("@serviceme/devtools-protocol");
|
|
514
539
|
var COPILOT_COMMAND2 = "copilot";
|
|
515
540
|
var DEFAULT_TIMEOUT_MS = 12e4;
|
|
516
541
|
function stripAnsi(text) {
|
|
@@ -544,18 +569,21 @@ async function copilotPrompt(options) {
|
|
|
544
569
|
});
|
|
545
570
|
const output = stripAnsi(result.stdout);
|
|
546
571
|
if (output.includes("I'm sorry, but I cannot assist") && result.stderr?.includes("Stream completed without a response")) {
|
|
547
|
-
throw (0,
|
|
548
|
-
|
|
572
|
+
throw (0, import_devtools_protocol3.createServicemeError)(
|
|
573
|
+
import_devtools_protocol3.COPILOT_ERROR_CODES.AUTH_REQUIRED,
|
|
549
574
|
"Copilot CLI returned a refusal response. This typically indicates an expired authentication token. Run `gh auth login` to re-authenticate.",
|
|
550
575
|
{ exitCode: 0, output, stderr: result.stderr }
|
|
551
576
|
);
|
|
552
577
|
}
|
|
553
578
|
return { output, exitCode: 0 };
|
|
554
579
|
} catch (error) {
|
|
580
|
+
if (error instanceof import_devtools_protocol3.ServicemeProtocolError) {
|
|
581
|
+
throw error;
|
|
582
|
+
}
|
|
555
583
|
const err = error;
|
|
556
584
|
if (err.code === "ETIMEDOUT") {
|
|
557
|
-
throw (0,
|
|
558
|
-
|
|
585
|
+
throw (0, import_devtools_protocol3.createServicemeError)(
|
|
586
|
+
import_devtools_protocol3.COPILOT_ERROR_CODES.TIMEOUT,
|
|
559
587
|
`Copilot prompt timed out after ${String(timeout)}ms.`
|
|
560
588
|
);
|
|
561
589
|
}
|
|
@@ -563,8 +591,8 @@ async function copilotPrompt(options) {
|
|
|
563
591
|
const output = stripAnsi(err.stdout ?? "");
|
|
564
592
|
const stderr = err.stderr ?? err.message ?? "";
|
|
565
593
|
if (output.includes("I'm sorry, but I cannot assist") || stderr.includes("Stream completed without a response")) {
|
|
566
|
-
throw (0,
|
|
567
|
-
|
|
594
|
+
throw (0, import_devtools_protocol3.createServicemeError)(
|
|
595
|
+
import_devtools_protocol3.COPILOT_ERROR_CODES.AUTH_REQUIRED,
|
|
568
596
|
"Copilot CLI returned a refusal response. This typically indicates an expired authentication token. Run `gh auth login` to re-authenticate.",
|
|
569
597
|
{ exitCode, output, stderr }
|
|
570
598
|
);
|
|
@@ -572,8 +600,8 @@ async function copilotPrompt(options) {
|
|
|
572
600
|
if (exitCode !== 0 && output) {
|
|
573
601
|
return { output, exitCode };
|
|
574
602
|
}
|
|
575
|
-
throw (0,
|
|
576
|
-
|
|
603
|
+
throw (0, import_devtools_protocol3.createServicemeError)(
|
|
604
|
+
import_devtools_protocol3.COPILOT_ERROR_CODES.EXECUTION_FAILED,
|
|
577
605
|
stderr || `Copilot exited with code ${String(exitCode)}.`,
|
|
578
606
|
{ exitCode, stderr }
|
|
579
607
|
);
|
|
@@ -581,7 +609,7 @@ async function copilotPrompt(options) {
|
|
|
581
609
|
}
|
|
582
610
|
|
|
583
611
|
// src/env/environmentInspector.ts
|
|
584
|
-
var
|
|
612
|
+
var import_devtools_protocol4 = require("@serviceme/devtools-protocol");
|
|
585
613
|
var DEFAULT_TOOL_CHECK_TIMEOUT_MS = 5e3;
|
|
586
614
|
var TOOL_CHECK_TIMEOUT_MS = {
|
|
587
615
|
nuget: 12e3,
|
|
@@ -597,17 +625,19 @@ var TOOL_CHECK_TIMEOUT_MS = {
|
|
|
597
625
|
var ERROR_CODE_NOT_FOUND = 127;
|
|
598
626
|
var ERROR_CODE_TIMEOUT = "ETIMEDOUT";
|
|
599
627
|
var EnvironmentInspector = class {
|
|
628
|
+
constructor(options = {}) {
|
|
629
|
+
this.runCommandFn = options.runCommand ?? runCommand;
|
|
630
|
+
this.platform = options.platform ?? process.platform;
|
|
631
|
+
}
|
|
600
632
|
async checkEnvironment() {
|
|
601
633
|
const results = await Promise.all(
|
|
602
|
-
|
|
603
|
-
async (tool) => [tool, await this.checkTool(tool)]
|
|
604
|
-
)
|
|
634
|
+
import_devtools_protocol4.KNOWN_ENVIRONMENT_TOOLS.map(async (tool) => [tool, await this.checkTool(tool)])
|
|
605
635
|
);
|
|
606
636
|
return Object.fromEntries(results);
|
|
607
637
|
}
|
|
608
638
|
async checkTool(toolName) {
|
|
609
639
|
if (!/^[a-zA-Z0-9-]+$/.test(toolName)) {
|
|
610
|
-
throw (0,
|
|
640
|
+
throw (0, import_devtools_protocol4.createServicemeError)("invalid_params", "Invalid tool name.");
|
|
611
641
|
}
|
|
612
642
|
try {
|
|
613
643
|
if (toolName === "nvm") {
|
|
@@ -629,8 +659,8 @@ var EnvironmentInspector = class {
|
|
|
629
659
|
}
|
|
630
660
|
async getToolPath(toolName) {
|
|
631
661
|
try {
|
|
632
|
-
const isWindows =
|
|
633
|
-
const result = await
|
|
662
|
+
const isWindows = this.platform === "win32";
|
|
663
|
+
const result = await this.runCommandFn(isWindows ? "where" : "which", {
|
|
634
664
|
args: [toolName],
|
|
635
665
|
timeoutMs: this.getToolTimeout(toolName)
|
|
636
666
|
});
|
|
@@ -647,14 +677,12 @@ var EnvironmentInspector = class {
|
|
|
647
677
|
*/
|
|
648
678
|
async getToolShimPath(toolName) {
|
|
649
679
|
try {
|
|
650
|
-
const result = await
|
|
680
|
+
const result = await this.runCommandFn("where", {
|
|
651
681
|
args: [toolName],
|
|
652
682
|
timeoutMs: this.getToolTimeout(toolName)
|
|
653
683
|
});
|
|
654
684
|
const candidates = result.stdout.split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0);
|
|
655
|
-
const cmdShim = candidates.find(
|
|
656
|
-
(line) => line.toLowerCase().endsWith(".cmd")
|
|
657
|
-
);
|
|
685
|
+
const cmdShim = candidates.find((line) => line.toLowerCase().endsWith(".cmd"));
|
|
658
686
|
return cmdShim ?? candidates[0];
|
|
659
687
|
} catch {
|
|
660
688
|
return void 0;
|
|
@@ -662,16 +690,16 @@ var EnvironmentInspector = class {
|
|
|
662
690
|
}
|
|
663
691
|
async getToolVersion(toolName) {
|
|
664
692
|
const invocation = await this.getVersionInvocation(toolName);
|
|
665
|
-
const result = await
|
|
693
|
+
const result = await this.runCommandFn(invocation.command, {
|
|
666
694
|
args: invocation.args,
|
|
667
695
|
timeoutMs: this.getToolTimeout(toolName)
|
|
668
696
|
});
|
|
669
697
|
return this.parseVersion(toolName, result.stdout || result.stderr);
|
|
670
698
|
}
|
|
671
699
|
async checkNvm() {
|
|
672
|
-
if (
|
|
700
|
+
if (this.platform === "win32") {
|
|
673
701
|
try {
|
|
674
|
-
const result = await
|
|
702
|
+
const result = await this.runCommandFn("cmd.exe", {
|
|
675
703
|
args: ["/c", "nvm version"],
|
|
676
704
|
timeoutMs: this.getToolTimeout("nvm")
|
|
677
705
|
});
|
|
@@ -688,7 +716,7 @@ var EnvironmentInspector = class {
|
|
|
688
716
|
}
|
|
689
717
|
}
|
|
690
718
|
try {
|
|
691
|
-
const result = await
|
|
719
|
+
const result = await this.runCommandFn("/bin/bash", {
|
|
692
720
|
args: [
|
|
693
721
|
"-lc",
|
|
694
722
|
'export NVM_DIR="$HOME/.nvm"; [ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh"; nvm --version'
|
|
@@ -716,7 +744,7 @@ var EnvironmentInspector = class {
|
|
|
716
744
|
};
|
|
717
745
|
}
|
|
718
746
|
try {
|
|
719
|
-
const result = await
|
|
747
|
+
const result = await this.runCommandFn("dotnet", {
|
|
720
748
|
args: ["nuget", "list", "source"],
|
|
721
749
|
timeoutMs: this.getToolTimeout("nuget")
|
|
722
750
|
});
|
|
@@ -737,7 +765,7 @@ var EnvironmentInspector = class {
|
|
|
737
765
|
}
|
|
738
766
|
}
|
|
739
767
|
async getVersionInvocation(toolName) {
|
|
740
|
-
const isWindows =
|
|
768
|
+
const isWindows = this.platform === "win32";
|
|
741
769
|
if (isWindows && ["npm", "pnpm", "nrm"].includes(toolName)) {
|
|
742
770
|
const shim = await this.getToolShimPath(toolName);
|
|
743
771
|
if (shim) {
|
|
@@ -791,7 +819,7 @@ var EnvironmentInspector = class {
|
|
|
791
819
|
const execError = error;
|
|
792
820
|
const message = execError.message || String(error);
|
|
793
821
|
const code = execError.code;
|
|
794
|
-
const isNotFound = message.includes("command not found") || message.includes("not recognized") || message.includes("ENOENT") || code === "ENOENT" || code === ERROR_CODE_NOT_FOUND;
|
|
822
|
+
const isNotFound = message.includes("command not found") || message.includes("not recognized") || message.includes("ENOENT") || message.includes("EACCES") || code === "ENOENT" || code === "EACCES" || code === ERROR_CODE_NOT_FOUND;
|
|
795
823
|
const isTimeout = code === ERROR_CODE_TIMEOUT || message.toLowerCase().includes("timed out");
|
|
796
824
|
return {
|
|
797
825
|
installed: false,
|
|
@@ -803,7 +831,7 @@ var EnvironmentInspector = class {
|
|
|
803
831
|
// src/image/imageTools.ts
|
|
804
832
|
var fs2 = __toESM(require("fs/promises"));
|
|
805
833
|
var path2 = __toESM(require("path"));
|
|
806
|
-
var
|
|
834
|
+
var import_devtools_protocol5 = require("@serviceme/devtools-protocol");
|
|
807
835
|
var SUPPORTED_FORMATS = [
|
|
808
836
|
".jpg",
|
|
809
837
|
".jpeg",
|
|
@@ -847,7 +875,7 @@ var ImageTools = class {
|
|
|
847
875
|
async compress(imagePath, options) {
|
|
848
876
|
const validation = await this.validate(imagePath, options.sharpModulePath);
|
|
849
877
|
if (!validation.valid) {
|
|
850
|
-
throw (0,
|
|
878
|
+
throw (0, import_devtools_protocol5.createServicemeError)(
|
|
851
879
|
"invalid_params",
|
|
852
880
|
`Invalid image file: ${imagePath}`
|
|
853
881
|
);
|
|
@@ -921,7 +949,7 @@ var ImageTools = class {
|
|
|
921
949
|
try {
|
|
922
950
|
return sharpModulePath ? require(sharpModulePath) : require("sharp");
|
|
923
951
|
} catch (error) {
|
|
924
|
-
throw (0,
|
|
952
|
+
throw (0, import_devtools_protocol5.createServicemeError)(
|
|
925
953
|
"internal_error",
|
|
926
954
|
`sharp is required for image operations: ${error instanceof Error ? error.message : String(error)}`
|
|
927
955
|
);
|
|
@@ -933,13 +961,13 @@ function createImageTools() {
|
|
|
933
961
|
}
|
|
934
962
|
|
|
935
963
|
// src/json/jsonTools.ts
|
|
936
|
-
var
|
|
964
|
+
var import_devtools_protocol6 = require("@serviceme/devtools-protocol");
|
|
937
965
|
var import_comment_json = require("comment-json");
|
|
938
966
|
var import_json5 = __toESM(require("json5"));
|
|
939
967
|
function createJsonTools() {
|
|
940
968
|
return {
|
|
941
969
|
sort(text, options) {
|
|
942
|
-
const finalOptions = { ...
|
|
970
|
+
const finalOptions = { ...import_devtools_protocol6.DEFAULT_JSON_SORT_OPTIONS, ...options };
|
|
943
971
|
const json = parseJson(text);
|
|
944
972
|
const sorted = sortObject(json, finalOptions);
|
|
945
973
|
return JSON.stringify(sorted, null, detectIndent(text));
|
|
@@ -975,7 +1003,7 @@ function parseJson(text) {
|
|
|
975
1003
|
} catch {
|
|
976
1004
|
}
|
|
977
1005
|
}
|
|
978
|
-
throw (0,
|
|
1006
|
+
throw (0, import_devtools_protocol6.createServicemeError)("json_invalid_input", "Invalid JSON format.");
|
|
979
1007
|
}
|
|
980
1008
|
function sortObject(obj, options) {
|
|
981
1009
|
if (Array.isArray(obj)) {
|
|
@@ -1069,58 +1097,51 @@ function createConsoleLogger(prefix = "serviceme") {
|
|
|
1069
1097
|
// src/project/projectTools.ts
|
|
1070
1098
|
var fs3 = __toESM(require("fs/promises"));
|
|
1071
1099
|
var path3 = __toESM(require("path"));
|
|
1072
|
-
var
|
|
1100
|
+
var import_devtools_protocol7 = require("@serviceme/devtools-protocol");
|
|
1073
1101
|
|
|
1074
1102
|
// src/utils/fileUtils.ts
|
|
1075
1103
|
var import_node_fs = require("fs");
|
|
1076
1104
|
var import_promises = require("fs/promises");
|
|
1077
1105
|
var import_node_path = require("path");
|
|
1078
|
-
var import_yauzl = require("yauzl");
|
|
1106
|
+
var import_yauzl = __toESM(require("yauzl"));
|
|
1079
1107
|
var unzipFile = (zipPath, dest) => {
|
|
1080
1108
|
return new Promise((resolve, reject) => {
|
|
1081
|
-
(
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
(
|
|
1085
|
-
|
|
1086
|
-
if (
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
entry
|
|
1098
|
-
(
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
resolve();
|
|
1118
|
-
});
|
|
1119
|
-
zipfile.on("error", (zipError) => {
|
|
1120
|
-
reject(zipError);
|
|
1121
|
-
});
|
|
1122
|
-
}
|
|
1123
|
-
);
|
|
1109
|
+
import_yauzl.default.open(zipPath, { lazyEntries: true }, (err, zipfile) => {
|
|
1110
|
+
if (err) return reject(err);
|
|
1111
|
+
if (!zipfile) return reject(new Error("Failed to open zip file."));
|
|
1112
|
+
zipfile.readEntry();
|
|
1113
|
+
zipfile.on("entry", (entry) => {
|
|
1114
|
+
if (/\/$/.test(entry.fileName)) {
|
|
1115
|
+
void (0, import_promises.mkdir)((0, import_node_path.join)(dest, entry.fileName), { recursive: true }).then(() => {
|
|
1116
|
+
zipfile.readEntry();
|
|
1117
|
+
}).catch(reject);
|
|
1118
|
+
} else {
|
|
1119
|
+
const outputPath = (0, import_node_path.join)(dest, entry.fileName);
|
|
1120
|
+
void (0, import_promises.mkdir)((0, import_node_path.dirname)(outputPath), { recursive: true }).then(() => {
|
|
1121
|
+
zipfile.openReadStream(
|
|
1122
|
+
entry,
|
|
1123
|
+
(streamError, readStream) => {
|
|
1124
|
+
if (streamError) return reject(streamError);
|
|
1125
|
+
if (!readStream) return reject(new Error("Failed to open zip entry stream."));
|
|
1126
|
+
const writeStream = (0, import_node_fs.createWriteStream)(outputPath);
|
|
1127
|
+
readStream.on("error", reject);
|
|
1128
|
+
writeStream.on("error", reject);
|
|
1129
|
+
writeStream.on("close", () => {
|
|
1130
|
+
zipfile.readEntry();
|
|
1131
|
+
});
|
|
1132
|
+
readStream.pipe(writeStream);
|
|
1133
|
+
}
|
|
1134
|
+
);
|
|
1135
|
+
}).catch(reject);
|
|
1136
|
+
}
|
|
1137
|
+
});
|
|
1138
|
+
zipfile.on("end", () => {
|
|
1139
|
+
resolve();
|
|
1140
|
+
});
|
|
1141
|
+
zipfile.on("error", (zipError) => {
|
|
1142
|
+
reject(zipError);
|
|
1143
|
+
});
|
|
1144
|
+
});
|
|
1124
1145
|
});
|
|
1125
1146
|
};
|
|
1126
1147
|
var tryLstat = async (targetPath) => {
|
|
@@ -1144,11 +1165,7 @@ var mergeEntry = async (sourcePath, destPath, overwrite) => {
|
|
|
1144
1165
|
await (0, import_promises.mkdir)(destPath, { recursive: true });
|
|
1145
1166
|
const children = await (0, import_promises.readdir)(sourcePath);
|
|
1146
1167
|
for (const child of children) {
|
|
1147
|
-
await mergeEntry(
|
|
1148
|
-
(0, import_node_path.join)(sourcePath, child),
|
|
1149
|
-
(0, import_node_path.join)(destPath, child),
|
|
1150
|
-
overwrite
|
|
1151
|
-
);
|
|
1168
|
+
await mergeEntry((0, import_node_path.join)(sourcePath, child), (0, import_node_path.join)(destPath, child), overwrite);
|
|
1152
1169
|
}
|
|
1153
1170
|
await (0, import_promises.rm)(sourcePath, { recursive: true, force: true });
|
|
1154
1171
|
return;
|
|
@@ -1225,7 +1242,7 @@ var ProjectTools = class {
|
|
|
1225
1242
|
}
|
|
1226
1243
|
async installDependencies(workspacePath, command) {
|
|
1227
1244
|
if (!command) {
|
|
1228
|
-
throw (0,
|
|
1245
|
+
throw (0, import_devtools_protocol7.createServicemeError)("invalid_params", "Expected install command.");
|
|
1229
1246
|
}
|
|
1230
1247
|
await runCommand(command, {
|
|
1231
1248
|
cwd: workspacePath,
|
|
@@ -1238,23 +1255,15 @@ var ProjectTools = class {
|
|
|
1238
1255
|
}
|
|
1239
1256
|
async makeScriptsExecutable(workspacePath) {
|
|
1240
1257
|
const isWindows = process.platform === "win32";
|
|
1241
|
-
const scripts = await this.findScripts(
|
|
1242
|
-
workspacePath,
|
|
1243
|
-
isWindows ? [".ps1", ".bat"] : [".sh"]
|
|
1244
|
-
);
|
|
1258
|
+
const scripts = await this.findScripts(workspacePath, isWindows ? [".ps1", ".bat"] : [".sh"]);
|
|
1245
1259
|
let updatedCount = 0;
|
|
1246
1260
|
if (isWindows) {
|
|
1247
|
-
for (const scriptPath of scripts.filter(
|
|
1248
|
-
(script) => script.endsWith(".ps1")
|
|
1249
|
-
)) {
|
|
1261
|
+
for (const scriptPath of scripts.filter((script) => script.endsWith(".ps1"))) {
|
|
1250
1262
|
try {
|
|
1251
|
-
await runCommand(
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
shell: true
|
|
1256
|
-
}
|
|
1257
|
-
);
|
|
1263
|
+
await runCommand(`powershell -Command "Unblock-File -Path '${scriptPath}'"`, {
|
|
1264
|
+
cwd: workspacePath,
|
|
1265
|
+
shell: true
|
|
1266
|
+
});
|
|
1258
1267
|
updatedCount += 1;
|
|
1259
1268
|
} catch {
|
|
1260
1269
|
}
|
|
@@ -1288,13 +1297,16 @@ var ProjectTools = class {
|
|
|
1288
1297
|
}
|
|
1289
1298
|
async runScaffoldPrune(workspacePath, preset) {
|
|
1290
1299
|
if (!preset) {
|
|
1291
|
-
throw (0,
|
|
1300
|
+
throw (0, import_devtools_protocol7.createServicemeError)("invalid_params", "Expected scaffold preset.");
|
|
1292
1301
|
}
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
];
|
|
1302
|
+
await this.ensurePresetManifest(workspacePath, preset);
|
|
1303
|
+
const pruneCommand = `pnpm run scaffold:prune -- --preset ${preset} --project-root .`;
|
|
1304
|
+
const initMetadataCommand = `pnpm run scaffold:init-metadata -- --preset ${preset} --project-root . --force`;
|
|
1305
|
+
const commands = [pruneCommand, initMetadataCommand];
|
|
1297
1306
|
for (const command of commands) {
|
|
1307
|
+
if (command === initMetadataCommand) {
|
|
1308
|
+
await this.ensurePresetManifest(workspacePath, preset);
|
|
1309
|
+
}
|
|
1298
1310
|
await runCommand(command, {
|
|
1299
1311
|
cwd: workspacePath,
|
|
1300
1312
|
shell: true
|
|
@@ -1306,6 +1318,40 @@ var ProjectTools = class {
|
|
|
1306
1318
|
commands
|
|
1307
1319
|
};
|
|
1308
1320
|
}
|
|
1321
|
+
async ensurePresetManifest(workspacePath, preset) {
|
|
1322
|
+
const presetManifestPath = path3.join(
|
|
1323
|
+
workspacePath,
|
|
1324
|
+
".ms-scaffold",
|
|
1325
|
+
"presets",
|
|
1326
|
+
`${preset}.json`
|
|
1327
|
+
);
|
|
1328
|
+
if (await this.pathExists(presetManifestPath)) {
|
|
1329
|
+
return;
|
|
1330
|
+
}
|
|
1331
|
+
const projectModePath = path3.join(workspacePath, ".ms-scaffold", "project-mode.json");
|
|
1332
|
+
if (!await this.pathExists(projectModePath)) {
|
|
1333
|
+
return;
|
|
1334
|
+
}
|
|
1335
|
+
const projectModeRaw = await fs3.readFile(projectModePath, "utf8");
|
|
1336
|
+
const projectMode = JSON.parse(projectModeRaw);
|
|
1337
|
+
const synthesizedPreset = {
|
|
1338
|
+
preset,
|
|
1339
|
+
selectedModules: Array.isArray(projectMode.selectedModules) ? projectMode.selectedModules : [],
|
|
1340
|
+
prunedModules: Array.isArray(projectMode.prunedModules) ? projectMode.prunedModules : [],
|
|
1341
|
+
exclude: [],
|
|
1342
|
+
recommendedFollowUps: [],
|
|
1343
|
+
managedFiles: [],
|
|
1344
|
+
mergeManagedFiles: [],
|
|
1345
|
+
userOwnedPaths: []
|
|
1346
|
+
};
|
|
1347
|
+
await fs3.mkdir(path3.dirname(presetManifestPath), { recursive: true });
|
|
1348
|
+
await fs3.writeFile(
|
|
1349
|
+
presetManifestPath,
|
|
1350
|
+
`${JSON.stringify(synthesizedPreset, null, 2)}
|
|
1351
|
+
`,
|
|
1352
|
+
"utf8"
|
|
1353
|
+
);
|
|
1354
|
+
}
|
|
1309
1355
|
async findScripts(dir, extensions) {
|
|
1310
1356
|
const results = [];
|
|
1311
1357
|
let entries;
|
|
@@ -1336,9 +1382,7 @@ var ProjectTools = class {
|
|
|
1336
1382
|
if (directoryNames.length === 1) {
|
|
1337
1383
|
return directoryNames[0] ?? null;
|
|
1338
1384
|
}
|
|
1339
|
-
const exactMatch = directoryNames.find(
|
|
1340
|
-
(directoryName) => directoryName === expectedDirName
|
|
1341
|
-
);
|
|
1385
|
+
const exactMatch = directoryNames.find((directoryName) => directoryName === expectedDirName);
|
|
1342
1386
|
if (exactMatch) {
|
|
1343
1387
|
return exactMatch;
|
|
1344
1388
|
}
|
|
@@ -1579,10 +1623,8 @@ var GithubCopilotCliExecutor = class {
|
|
|
1579
1623
|
windowsHide: true
|
|
1580
1624
|
});
|
|
1581
1625
|
if (child.pid) {
|
|
1582
|
-
writeDiagnostic(
|
|
1583
|
-
|
|
1584
|
-
`
|
|
1585
|
-
);
|
|
1626
|
+
writeDiagnostic(`[GithubCopilotCliExecutor] spawned child PID=${child.pid}
|
|
1627
|
+
`);
|
|
1586
1628
|
}
|
|
1587
1629
|
const timeoutMs = execution.timeoutMs;
|
|
1588
1630
|
const timer = timeoutMs != null ? setTimeout(() => {
|
|
@@ -1600,15 +1642,13 @@ var GithubCopilotCliExecutor = class {
|
|
|
1600
1642
|
child.stdout.on("data", (chunk) => {
|
|
1601
1643
|
const data = chunk.toString();
|
|
1602
1644
|
stdoutBuf += data;
|
|
1603
|
-
if (stdoutBuf.length > MAX_OUTPUT_BYTES)
|
|
1604
|
-
stdoutBuf = stdoutBuf.slice(-MAX_OUTPUT_BYTES);
|
|
1645
|
+
if (stdoutBuf.length > MAX_OUTPUT_BYTES) stdoutBuf = stdoutBuf.slice(-MAX_OUTPUT_BYTES);
|
|
1605
1646
|
onOutput("stdout", data);
|
|
1606
1647
|
});
|
|
1607
1648
|
child.stderr.on("data", (chunk) => {
|
|
1608
1649
|
const data = chunk.toString();
|
|
1609
1650
|
stderrBuf += data;
|
|
1610
|
-
if (stderrBuf.length > MAX_OUTPUT_BYTES)
|
|
1611
|
-
stderrBuf = stderrBuf.slice(-MAX_OUTPUT_BYTES);
|
|
1651
|
+
if (stderrBuf.length > MAX_OUTPUT_BYTES) stderrBuf = stderrBuf.slice(-MAX_OUTPUT_BYTES);
|
|
1612
1652
|
onOutput("stderr", data);
|
|
1613
1653
|
});
|
|
1614
1654
|
child.on("close", (code) => {
|
|
@@ -1926,7 +1966,7 @@ function getExecutor(taskType) {
|
|
|
1926
1966
|
var import_node_crypto = require("crypto");
|
|
1927
1967
|
var fs8 = __toESM(require("fs"));
|
|
1928
1968
|
var path7 = __toESM(require("path"));
|
|
1929
|
-
var
|
|
1969
|
+
var import_devtools_protocol8 = require("@serviceme/devtools-protocol");
|
|
1930
1970
|
var CONFIG_DIR3 = ".serviceme";
|
|
1931
1971
|
var CONFIG_FILE = "scheduled-tasks.json";
|
|
1932
1972
|
function emptyConfig() {
|
|
@@ -1937,10 +1977,7 @@ function isRecord(value) {
|
|
|
1937
1977
|
}
|
|
1938
1978
|
function requireNonEmptyString(payload, field, taskType) {
|
|
1939
1979
|
if (!isRecord(payload) || typeof payload[field] !== "string" || !payload[field].trim()) {
|
|
1940
|
-
throw (0,
|
|
1941
|
-
"invalid_payload",
|
|
1942
|
-
`${taskType} payload ${field} is required`
|
|
1943
|
-
);
|
|
1980
|
+
throw (0, import_devtools_protocol8.createServicemeError)("invalid_payload", `${taskType} payload ${field} is required`);
|
|
1944
1981
|
}
|
|
1945
1982
|
}
|
|
1946
1983
|
function validateTaskPayload(taskType, payload) {
|
|
@@ -2103,9 +2140,7 @@ var TaskExecutionEngine = class {
|
|
|
2103
2140
|
if (policy === "reject") {
|
|
2104
2141
|
const existingIds = this.taskExecutions.get(snapshot.taskId);
|
|
2105
2142
|
if (existingIds && existingIds.size > 0) {
|
|
2106
|
-
throw new Error(
|
|
2107
|
-
`TASK_ALREADY_RUNNING: Task ${snapshot.taskId} is already running`
|
|
2108
|
-
);
|
|
2143
|
+
throw new Error(`TASK_ALREADY_RUNNING: Task ${snapshot.taskId} is already running`);
|
|
2109
2144
|
}
|
|
2110
2145
|
}
|
|
2111
2146
|
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -2370,7 +2405,7 @@ var TaskLogManager = class {
|
|
|
2370
2405
|
var TICK_INTERVAL = 1e3;
|
|
2371
2406
|
var MIN_SCHEDULE_INTERVAL = 1e3;
|
|
2372
2407
|
var SchedulerDaemon = class {
|
|
2373
|
-
constructor(workspacePath) {
|
|
2408
|
+
constructor(workspacePath, options = {}) {
|
|
2374
2409
|
this.tickTimer = null;
|
|
2375
2410
|
this.watcher = null;
|
|
2376
2411
|
this.running = false;
|
|
@@ -2383,6 +2418,7 @@ var SchedulerDaemon = class {
|
|
|
2383
2418
|
this.logManager = new TaskLogManager(workspacePath);
|
|
2384
2419
|
this.pidManager = new PidManager(workspacePath);
|
|
2385
2420
|
this.logger = new DaemonLogger(workspacePath);
|
|
2421
|
+
this.getExecutor = options.getExecutor ?? getExecutor;
|
|
2386
2422
|
}
|
|
2387
2423
|
start() {
|
|
2388
2424
|
if (this.running) return;
|
|
@@ -2488,7 +2524,7 @@ var SchedulerDaemon = class {
|
|
|
2488
2524
|
this.workspacePath
|
|
2489
2525
|
);
|
|
2490
2526
|
validateTaskPayload(task.taskType, executionPayload);
|
|
2491
|
-
const executor = getExecutor(task.taskType);
|
|
2527
|
+
const executor = this.getExecutor(task.taskType);
|
|
2492
2528
|
const result = await executor.execute(executionPayload);
|
|
2493
2529
|
const finishedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
2494
2530
|
const durationMs = Date.now() - startMs;
|
|
@@ -2585,6 +2621,7 @@ function matchCronField(field, value) {
|
|
|
2585
2621
|
}
|
|
2586
2622
|
|
|
2587
2623
|
// src/skills/SkillCatalogClient.ts
|
|
2624
|
+
var import_devtools_protocol9 = require("@serviceme/devtools-protocol");
|
|
2588
2625
|
var SkillCatalogClient = class {
|
|
2589
2626
|
constructor(options = {}) {
|
|
2590
2627
|
this.fetchImpl = options.fetchImpl ?? fetch;
|
|
@@ -2592,10 +2629,10 @@ var SkillCatalogClient = class {
|
|
|
2592
2629
|
}
|
|
2593
2630
|
async getCatalog() {
|
|
2594
2631
|
if (!this.baseUrl) {
|
|
2595
|
-
|
|
2596
|
-
|
|
2597
|
-
|
|
2598
|
-
|
|
2632
|
+
throw (0, import_devtools_protocol9.createServicemeError)(
|
|
2633
|
+
"workspace_not_found",
|
|
2634
|
+
"Skill catalog baseUrl is not configured."
|
|
2635
|
+
);
|
|
2599
2636
|
}
|
|
2600
2637
|
const response = await this.fetchImpl(
|
|
2601
2638
|
`${this.baseUrl}/api/v1/marketplace/skills`
|
|
@@ -2609,6 +2646,30 @@ var SkillCatalogClient = class {
|
|
|
2609
2646
|
fetchedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
2610
2647
|
};
|
|
2611
2648
|
}
|
|
2649
|
+
async downloadSkill(remoteId) {
|
|
2650
|
+
if (!this.baseUrl) {
|
|
2651
|
+
throw (0, import_devtools_protocol9.createServicemeError)(
|
|
2652
|
+
"workspace_not_found",
|
|
2653
|
+
"Skill catalog baseUrl is not configured."
|
|
2654
|
+
);
|
|
2655
|
+
}
|
|
2656
|
+
const response = await this.fetchImpl(
|
|
2657
|
+
`${this.baseUrl}/api/v1/marketplace/skills/download/${remoteId}`
|
|
2658
|
+
);
|
|
2659
|
+
if (!response.ok) {
|
|
2660
|
+
if (response.status === 404) {
|
|
2661
|
+
throw (0, import_devtools_protocol9.createServicemeError)(
|
|
2662
|
+
"not_found",
|
|
2663
|
+
`Skill '${remoteId}' not found`
|
|
2664
|
+
);
|
|
2665
|
+
}
|
|
2666
|
+
throw new Error(
|
|
2667
|
+
`Failed to download skill ${remoteId}: ${response.status}`
|
|
2668
|
+
);
|
|
2669
|
+
}
|
|
2670
|
+
const payload = await response.json();
|
|
2671
|
+
return payload.data?.files ?? [];
|
|
2672
|
+
}
|
|
2612
2673
|
};
|
|
2613
2674
|
|
|
2614
2675
|
// src/skills/SkillReconciler.ts
|
|
@@ -2745,6 +2806,22 @@ var SkillStore = class {
|
|
|
2745
2806
|
return false;
|
|
2746
2807
|
}
|
|
2747
2808
|
}
|
|
2809
|
+
async writeSkillFiles(skillId, scope, files) {
|
|
2810
|
+
const root = scope === "workspace" ? path9.join(this.workspacePath, WORKSPACE_SKILLS_ROOT_RELATIVE) : this.userSkillsRoot;
|
|
2811
|
+
const targetDir = path9.join(root, skillId);
|
|
2812
|
+
await this.fileSystem.mkdir(targetDir, { recursive: true });
|
|
2813
|
+
for (const file of files) {
|
|
2814
|
+
const filePath = path9.join(targetDir, file.path);
|
|
2815
|
+
await this.fileSystem.mkdir(path9.dirname(filePath), { recursive: true });
|
|
2816
|
+
await this.fileSystem.writeFile(filePath, file.content, "utf-8");
|
|
2817
|
+
if (file.executable) {
|
|
2818
|
+
try {
|
|
2819
|
+
await this.fileSystem.chmod(filePath, 493);
|
|
2820
|
+
} catch {
|
|
2821
|
+
}
|
|
2822
|
+
}
|
|
2823
|
+
}
|
|
2824
|
+
}
|
|
2748
2825
|
};
|
|
2749
2826
|
// Annotate the CommonJS export names for ESM import in node:
|
|
2750
2827
|
0 && (module.exports = {
|