@ductape/mcp 0.1.5 → 0.1.7
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.js +71 -1
- package/package.json +1 -1
- package/src/index.ts +76 -1
package/dist/index.js
CHANGED
|
@@ -806,6 +806,9 @@ function buildSnippet(language, payload, operationFamily, method) {
|
|
|
806
806
|
: buildTypeScriptSnippet(payload, operationFamily, method);
|
|
807
807
|
}
|
|
808
808
|
// ─── CLI helpers ─────────────────────────────────────────────────────────────
|
|
809
|
+
// Per-process cache: avoids re-running whoami / workspaces use on every call.
|
|
810
|
+
let authState = 'unknown';
|
|
811
|
+
let workspaceSynced = false;
|
|
809
812
|
const ADMIN_SUBCOMMANDS = [
|
|
810
813
|
'login', 'logout', 'whoami',
|
|
811
814
|
'profiles',
|
|
@@ -829,6 +832,29 @@ function checkCli() {
|
|
|
829
832
|
return { available: false };
|
|
830
833
|
}
|
|
831
834
|
}
|
|
835
|
+
function checkLoginState() {
|
|
836
|
+
try {
|
|
837
|
+
execSync('ductape whoami --json', { encoding: 'utf8', timeout: 5000, stdio: ['pipe', 'pipe', 'pipe'] });
|
|
838
|
+
authState = 'ok';
|
|
839
|
+
return 'ok';
|
|
840
|
+
}
|
|
841
|
+
catch {
|
|
842
|
+
authState = 'none';
|
|
843
|
+
return 'none';
|
|
844
|
+
}
|
|
845
|
+
}
|
|
846
|
+
function syncWorkspace() {
|
|
847
|
+
const target = process.env.DUCTAPE_WORKSPACE;
|
|
848
|
+
workspaceSynced = true; // mark done regardless so we don't retry on every call
|
|
849
|
+
if (!target)
|
|
850
|
+
return;
|
|
851
|
+
try {
|
|
852
|
+
execSync(`ductape workspaces use "${target}"`, { encoding: 'utf8', timeout: 10000, stdio: ['pipe', 'pipe', 'pipe'] });
|
|
853
|
+
}
|
|
854
|
+
catch {
|
|
855
|
+
// best-effort; if it fails the user will see workspace-mismatch errors on subsequent commands
|
|
856
|
+
}
|
|
857
|
+
}
|
|
832
858
|
function runCli(command) {
|
|
833
859
|
const first = command.trim().split(/\s+/)[0];
|
|
834
860
|
if (!ADMIN_SUBCOMMANDS.includes(first)) {
|
|
@@ -837,8 +863,14 @@ function runCli(command) {
|
|
|
837
863
|
output: `Subcommand "${first}" is not in the allowed admin subcommand list. Allowed: ${ADMIN_SUBCOMMANDS.join(', ')}.`,
|
|
838
864
|
};
|
|
839
865
|
}
|
|
866
|
+
// Auto-inject --workspace on login if DUCTAPE_WORKSPACE is set and caller hasn't specified one
|
|
867
|
+
let finalCommand = command;
|
|
868
|
+
const ws = process.env.DUCTAPE_WORKSPACE;
|
|
869
|
+
if (first === 'login' && ws && !command.includes('--workspace') && !command.includes('--skip-workspace-select')) {
|
|
870
|
+
finalCommand = `${command} --workspace "${ws}"`;
|
|
871
|
+
}
|
|
840
872
|
try {
|
|
841
|
-
const output = execSync(`ductape ${
|
|
873
|
+
const output = execSync(`ductape ${finalCommand}`, {
|
|
842
874
|
encoding: 'utf8',
|
|
843
875
|
timeout: 30000,
|
|
844
876
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
@@ -937,7 +969,45 @@ async function main() {
|
|
|
937
969
|
isError: true,
|
|
938
970
|
};
|
|
939
971
|
}
|
|
972
|
+
const firstWord = args.command.trim().split(/\s+/)[0];
|
|
973
|
+
const isAuthCommand = firstWord === 'login' || firstWord === 'logout';
|
|
974
|
+
if (!isAuthCommand) {
|
|
975
|
+
// Check login status once per process (cached after first call)
|
|
976
|
+
if (authState === 'unknown') {
|
|
977
|
+
checkLoginState();
|
|
978
|
+
}
|
|
979
|
+
if (authState === 'none') {
|
|
980
|
+
const wsFlag = process.env.DUCTAPE_WORKSPACE ? ` --workspace "${process.env.DUCTAPE_WORKSPACE}"` : '';
|
|
981
|
+
return {
|
|
982
|
+
content: [{
|
|
983
|
+
type: 'text',
|
|
984
|
+
text: [
|
|
985
|
+
'Not logged in to the Ductape CLI.',
|
|
986
|
+
'',
|
|
987
|
+
'Ask the user for their Ductape email and password, then call:',
|
|
988
|
+
` ductape_cli("login --email <email> --password <password>${wsFlag}")`,
|
|
989
|
+
'',
|
|
990
|
+
'Or the user can run `ductape login` in their terminal and then retry.',
|
|
991
|
+
].join('\n'),
|
|
992
|
+
}],
|
|
993
|
+
isError: true,
|
|
994
|
+
};
|
|
995
|
+
}
|
|
996
|
+
// Sync to the configured workspace once per process (best-effort)
|
|
997
|
+
if (!workspaceSynced) {
|
|
998
|
+
syncWorkspace();
|
|
999
|
+
}
|
|
1000
|
+
}
|
|
940
1001
|
const result = runCli(args.command);
|
|
1002
|
+
// Update cached state after auth commands
|
|
1003
|
+
if (firstWord === 'login' && result.success) {
|
|
1004
|
+
authState = 'ok';
|
|
1005
|
+
workspaceSynced = false; // re-sync workspace after fresh login
|
|
1006
|
+
}
|
|
1007
|
+
if (firstWord === 'logout' && result.success) {
|
|
1008
|
+
authState = 'none';
|
|
1009
|
+
workspaceSynced = false;
|
|
1010
|
+
}
|
|
941
1011
|
return {
|
|
942
1012
|
content: [{ type: 'text', text: result.output || '(no output)' }],
|
|
943
1013
|
...(result.success ? {} : { isError: true }),
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -850,6 +850,10 @@ function buildSnippet(
|
|
|
850
850
|
|
|
851
851
|
// ─── CLI helpers ─────────────────────────────────────────────────────────────
|
|
852
852
|
|
|
853
|
+
// Per-process cache: avoids re-running whoami / workspaces use on every call.
|
|
854
|
+
let authState: 'unknown' | 'ok' | 'none' = 'unknown';
|
|
855
|
+
let workspaceSynced = false;
|
|
856
|
+
|
|
853
857
|
const ADMIN_SUBCOMMANDS = [
|
|
854
858
|
'login', 'logout', 'whoami',
|
|
855
859
|
'profiles',
|
|
@@ -874,6 +878,28 @@ function checkCli(): { available: boolean; version?: string } {
|
|
|
874
878
|
}
|
|
875
879
|
}
|
|
876
880
|
|
|
881
|
+
function checkLoginState(): 'ok' | 'none' {
|
|
882
|
+
try {
|
|
883
|
+
execSync('ductape whoami --json', { encoding: 'utf8', timeout: 5000, stdio: ['pipe', 'pipe', 'pipe'] });
|
|
884
|
+
authState = 'ok';
|
|
885
|
+
return 'ok';
|
|
886
|
+
} catch {
|
|
887
|
+
authState = 'none';
|
|
888
|
+
return 'none';
|
|
889
|
+
}
|
|
890
|
+
}
|
|
891
|
+
|
|
892
|
+
function syncWorkspace(): void {
|
|
893
|
+
const target = process.env.DUCTAPE_WORKSPACE;
|
|
894
|
+
workspaceSynced = true; // mark done regardless so we don't retry on every call
|
|
895
|
+
if (!target) return;
|
|
896
|
+
try {
|
|
897
|
+
execSync(`ductape workspaces use "${target}"`, { encoding: 'utf8', timeout: 10000, stdio: ['pipe', 'pipe', 'pipe'] });
|
|
898
|
+
} catch {
|
|
899
|
+
// best-effort; if it fails the user will see workspace-mismatch errors on subsequent commands
|
|
900
|
+
}
|
|
901
|
+
}
|
|
902
|
+
|
|
877
903
|
function runCli(command: string): { success: boolean; output: string } {
|
|
878
904
|
const first = command.trim().split(/\s+/)[0];
|
|
879
905
|
if (!ADMIN_SUBCOMMANDS.includes(first)) {
|
|
@@ -882,8 +908,14 @@ function runCli(command: string): { success: boolean; output: string } {
|
|
|
882
908
|
output: `Subcommand "${first}" is not in the allowed admin subcommand list. Allowed: ${ADMIN_SUBCOMMANDS.join(', ')}.`,
|
|
883
909
|
};
|
|
884
910
|
}
|
|
911
|
+
// Auto-inject --workspace on login if DUCTAPE_WORKSPACE is set and caller hasn't specified one
|
|
912
|
+
let finalCommand = command;
|
|
913
|
+
const ws = process.env.DUCTAPE_WORKSPACE;
|
|
914
|
+
if (first === 'login' && ws && !command.includes('--workspace') && !command.includes('--skip-workspace-select')) {
|
|
915
|
+
finalCommand = `${command} --workspace "${ws}"`;
|
|
916
|
+
}
|
|
885
917
|
try {
|
|
886
|
-
const output = execSync(`ductape ${
|
|
918
|
+
const output = execSync(`ductape ${finalCommand}`, {
|
|
887
919
|
encoding: 'utf8',
|
|
888
920
|
timeout: 30000,
|
|
889
921
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
@@ -995,7 +1027,50 @@ async function main() {
|
|
|
995
1027
|
isError: true,
|
|
996
1028
|
};
|
|
997
1029
|
}
|
|
1030
|
+
|
|
1031
|
+
const firstWord = args.command.trim().split(/\s+/)[0];
|
|
1032
|
+
const isAuthCommand = firstWord === 'login' || firstWord === 'logout';
|
|
1033
|
+
|
|
1034
|
+
if (!isAuthCommand) {
|
|
1035
|
+
// Check login status once per process (cached after first call)
|
|
1036
|
+
if (authState === 'unknown') {
|
|
1037
|
+
checkLoginState();
|
|
1038
|
+
}
|
|
1039
|
+
if (authState === 'none') {
|
|
1040
|
+
const wsFlag = process.env.DUCTAPE_WORKSPACE ? ` --workspace "${process.env.DUCTAPE_WORKSPACE}"` : '';
|
|
1041
|
+
return {
|
|
1042
|
+
content: [{
|
|
1043
|
+
type: 'text',
|
|
1044
|
+
text: [
|
|
1045
|
+
'Not logged in to the Ductape CLI.',
|
|
1046
|
+
'',
|
|
1047
|
+
'Ask the user for their Ductape email and password, then call:',
|
|
1048
|
+
` ductape_cli("login --email <email> --password <password>${wsFlag}")`,
|
|
1049
|
+
'',
|
|
1050
|
+
'Or the user can run `ductape login` in their terminal and then retry.',
|
|
1051
|
+
].join('\n'),
|
|
1052
|
+
}],
|
|
1053
|
+
isError: true,
|
|
1054
|
+
};
|
|
1055
|
+
}
|
|
1056
|
+
// Sync to the configured workspace once per process (best-effort)
|
|
1057
|
+
if (!workspaceSynced) {
|
|
1058
|
+
syncWorkspace();
|
|
1059
|
+
}
|
|
1060
|
+
}
|
|
1061
|
+
|
|
998
1062
|
const result = runCli(args.command);
|
|
1063
|
+
|
|
1064
|
+
// Update cached state after auth commands
|
|
1065
|
+
if (firstWord === 'login' && result.success) {
|
|
1066
|
+
authState = 'ok';
|
|
1067
|
+
workspaceSynced = false; // re-sync workspace after fresh login
|
|
1068
|
+
}
|
|
1069
|
+
if (firstWord === 'logout' && result.success) {
|
|
1070
|
+
authState = 'none';
|
|
1071
|
+
workspaceSynced = false;
|
|
1072
|
+
}
|
|
1073
|
+
|
|
999
1074
|
return {
|
|
1000
1075
|
content: [{ type: 'text', text: result.output || '(no output)' }],
|
|
1001
1076
|
...(result.success ? {} : { isError: true }),
|