@nuvlore/extension-access-pagerduty 0.1.1
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/LICENSE +202 -0
- package/README.md +3 -0
- package/package.json +52 -0
- package/tools/pagerduty_sso_incident.mjs +32 -0
- package/tools/pagerduty_sso_incidents.mjs +36 -0
- package/tools/pagerduty_sso_oncalls.mjs +36 -0
- package/tools/pagerduty_sso_read.mjs +34 -0
- package/tools/pagerduty_sso_services.mjs +33 -0
- package/tools/pagerduty_sso_verify.mjs +26 -0
- package/vendor/extension-sso/LICENSE +202 -0
- package/vendor/extension-sso/README.md +35 -0
- package/vendor/extension-sso/commands/okta-login.md +10 -0
- package/vendor/extension-sso/package.json +51 -0
- package/vendor/extension-sso/skills/workday-okta-auth/SKILL.md +20 -0
- package/vendor/extension-sso/src/autoAuth.mjs +25 -0
- package/vendor/extension-sso/src/browserLogin.mjs +1 -0
- package/vendor/extension-sso/src/chromeCookies.mjs +1 -0
- package/vendor/extension-sso/src/cookieJar.mjs +1 -0
- package/vendor/extension-sso/src/extensionAccess.mjs +173 -0
- package/vendor/extension-sso/src/htmlSessionExtract.mjs +1 -0
- package/vendor/extension-sso/src/oktaAppAccess.mjs +133 -0
- package/vendor/extension-sso/src/oktaAppCatalog.mjs +118 -0
- package/vendor/extension-sso/src/oktaAppRead.mjs +119 -0
- package/vendor/extension-sso/src/oktaConfig.mjs +12 -0
- package/vendor/extension-sso/src/oktaSession.mjs +32 -0
- package/vendor/extension-sso/src/serviceOperations.mjs +407 -0
- package/vendor/extension-sso/src/serviceReadSearch.mjs +395 -0
- package/vendor/extension-sso/src/serviceReads.mjs +109 -0
- package/vendor/extension-sso/src/serviceRegistry.mjs +497 -0
- package/vendor/extension-sso/src/sessionAuth.mjs +339 -0
- package/vendor/extension-sso/src/sessionManager.mjs +212 -0
- package/vendor/extension-sso/src/sessionValidate.mjs +74 -0
- package/vendor/extension-sso/src/ssoConfig.mjs +31 -0
- package/vendor/extension-sso/src/ssoHttpRead.mjs +292 -0
- package/vendor/extension-sso/tools/extension-access-tools.shared.mjs +16 -0
- package/vendor/extension-sso/tools/okta-app-tools.shared.mjs +5 -0
- package/vendor/extension-sso/tools/okta-tools.shared.mjs +18 -0
- package/vendor/extension-sso/tools/workday_extension_read.mjs +51 -0
- package/vendor/extension-sso/tools/workday_extension_read_access.mjs +65 -0
- package/vendor/extension-sso/tools/workday_list_extension_access.mjs +39 -0
- package/vendor/extension-sso/tools/workday_list_okta_apps.mjs +18 -0
- package/vendor/extension-sso/tools/workday_list_service_operations.mjs +41 -0
- package/vendor/extension-sso/tools/workday_list_service_read_search_capabilities.mjs +34 -0
- package/vendor/extension-sso/tools/workday_list_services.mjs +31 -0
- package/vendor/extension-sso/tools/workday_okta_app_probe_all.mjs +24 -0
- package/vendor/extension-sso/tools/workday_okta_app_read.mjs +30 -0
- package/vendor/extension-sso/tools/workday_okta_app_read_access.mjs +25 -0
- package/vendor/extension-sso/tools/workday_okta_auth_header.mjs +58 -0
- package/vendor/extension-sso/tools/workday_okta_login.mjs +65 -0
- package/vendor/extension-sso/tools/workday_okta_open_app.mjs +63 -0
- package/vendor/extension-sso/tools/workday_okta_open_service.mjs +63 -0
- package/vendor/extension-sso/tools/workday_okta_status.mjs +35 -0
- package/vendor/extension-sso/tools/workday_service_auth.mjs +65 -0
- package/vendor/extension-sso/tools/workday_service_operation_read.mjs +51 -0
- package/vendor/extension-sso/tools/workday_service_read.mjs +56 -0
- package/vendor/extension-sso/tools/workday_service_search.mjs +62 -0
- package/vendor/extension-sso/tools/workday_sso_cookie_header.mjs +59 -0
- package/vendor/extension-sso/vendor/extension-browser-sso/LICENSE +202 -0
- package/vendor/extension-sso/vendor/extension-browser-sso/README.md +16 -0
- package/vendor/extension-sso/vendor/extension-browser-sso/package.json +47 -0
- package/vendor/extension-sso/vendor/extension-browser-sso/src/autoAuth.mjs +47 -0
- package/vendor/extension-sso/vendor/extension-browser-sso/src/browserHttpRead.mjs +76 -0
- package/vendor/extension-sso/vendor/extension-browser-sso/src/browserLogin.mjs +24 -0
- package/vendor/extension-sso/vendor/extension-browser-sso/src/chromeCookies.mjs +192 -0
- package/vendor/extension-sso/vendor/extension-browser-sso/src/cookieJar.mjs +132 -0
- package/vendor/extension-sso/vendor/extension-browser-sso/src/extensions/toolkit/devops-data-paths.mjs +222 -0
- package/vendor/extension-sso/vendor/extension-browser-sso/src/extensions/toolkit/devops-diagnostics.mjs +440 -0
- package/vendor/extension-sso/vendor/extension-browser-sso/src/extensions/toolkit/enterprise-api-read.mjs +180 -0
- package/vendor/extension-sso/vendor/extension-browser-sso/src/extensions/toolkit/read-only-command-pack.mjs +1 -0
- package/vendor/extension-sso/vendor/extension-browser-sso/src/extensions/toolkit/read-only-plan.mjs +45 -0
- package/vendor/extension-sso/vendor/extension-browser-sso/src/extensions/toolkit/read-only-shell-policy.d.mts +26 -0
- package/vendor/extension-sso/vendor/extension-browser-sso/src/extensions/toolkit/read-only-shell-policy.mjs +170 -0
- package/vendor/extension-sso/vendor/extension-browser-sso/src/htmlSessionExtract.mjs +64 -0
- package/vendor/extension-sso/vendor/extension-read-only-toolkit/LICENSE +202 -0
- package/vendor/extension-sso/vendor/extension-read-only-toolkit/README.md +29 -0
- package/vendor/extension-sso/vendor/extension-read-only-toolkit/package.json +43 -0
- package/vendor/extension-sso/vendor/extension-read-only-toolkit/src/devops-data-paths.mjs +222 -0
- package/vendor/extension-sso/vendor/extension-read-only-toolkit/src/devops-diagnostics.mjs +440 -0
- package/vendor/extension-sso/vendor/extension-read-only-toolkit/src/enterprise-api-read.mjs +180 -0
- package/vendor/extension-sso/vendor/extension-read-only-toolkit/src/read-only-command-pack.mjs +1 -0
- package/vendor/extension-sso/vendor/extension-read-only-toolkit/src/read-only-plan.mjs +45 -0
- package/vendor/extension-sso/vendor/extension-read-only-toolkit/src/read-only-shell-policy.d.mts +26 -0
- package/vendor/extension-sso/vendor/extension-read-only-toolkit/src/read-only-shell-policy.mjs +170 -0
|
@@ -0,0 +1,395 @@
|
|
|
1
|
+
import { existsSync, readdirSync, readFileSync } from "node:fs";
|
|
2
|
+
import { dirname, join } from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
import { extensionReadGet } from "./extensionAccess.mjs";
|
|
5
|
+
import { getWorkdayService, listWorkdayServices } from "./serviceRegistry.mjs";
|
|
6
|
+
import { buildServiceOperationInput, getServiceOperation, readServiceOperation } from "./serviceOperations.mjs";
|
|
7
|
+
|
|
8
|
+
const EXTENSIONS_DIR = join(dirname(fileURLToPath(import.meta.url)), "../..");
|
|
9
|
+
|
|
10
|
+
const SEARCH_STRATEGIES = {
|
|
11
|
+
jira: {
|
|
12
|
+
mode: "structured-operation",
|
|
13
|
+
operation: "search",
|
|
14
|
+
description: "Jira JQL search.",
|
|
15
|
+
buildParams: ({ query, maxResults = 25, fields }) => ({ jql: query, maxResults, fields })
|
|
16
|
+
},
|
|
17
|
+
confluence: {
|
|
18
|
+
mode: "structured-operation",
|
|
19
|
+
operation: "search",
|
|
20
|
+
description: "Confluence CQL search.",
|
|
21
|
+
buildParams: ({ query, limit = 25, start, expand }) => ({ cql: query, limit, start, expand })
|
|
22
|
+
},
|
|
23
|
+
pagerduty: {
|
|
24
|
+
mode: "structured-operation",
|
|
25
|
+
operation: "incidents",
|
|
26
|
+
description: "PagerDuty incident list filtered by status/service/time.",
|
|
27
|
+
buildParams: ({ statuses, service_ids, since, until, limit = 25 }) => ({ statuses, service_ids, since, until, limit })
|
|
28
|
+
},
|
|
29
|
+
repository: {
|
|
30
|
+
mode: "structured-operation",
|
|
31
|
+
operation: "search_gavc",
|
|
32
|
+
description: "Artifactory Maven GAVC search.",
|
|
33
|
+
buildParams: ({ g, a, v, c, repos }) => ({ g, a, v, c, repos })
|
|
34
|
+
},
|
|
35
|
+
pharos: {
|
|
36
|
+
mode: "structured-operation",
|
|
37
|
+
operation: "search",
|
|
38
|
+
description: "Pharos API search endpoint.",
|
|
39
|
+
buildParams: ({ query, limit = 25 }) => ({ query, limit })
|
|
40
|
+
},
|
|
41
|
+
teamcity: {
|
|
42
|
+
mode: "structured-operation",
|
|
43
|
+
operation: "builds",
|
|
44
|
+
description: "TeamCity builds locator search.",
|
|
45
|
+
buildParams: ({ query, locator, limit = 25 }) => ({ locator: locator ?? query ?? `count:${limit}` })
|
|
46
|
+
},
|
|
47
|
+
bamboo: {
|
|
48
|
+
mode: "structured-operation",
|
|
49
|
+
operation: "plan_results",
|
|
50
|
+
description: "Bamboo plan result search. Requires planKey.",
|
|
51
|
+
required: ["planKey"],
|
|
52
|
+
buildParams: ({ planKey, maxResults = 25, startIndex, expand }) => ({ planKey, maxResults, startIndex, expand })
|
|
53
|
+
},
|
|
54
|
+
bitbucket: {
|
|
55
|
+
mode: "structured-operation",
|
|
56
|
+
operation: "pull_requests",
|
|
57
|
+
description: "Bitbucket pull request list/search. Requires projectKey and repoSlug.",
|
|
58
|
+
required: ["projectKey", "repoSlug"],
|
|
59
|
+
buildParams: ({ projectKey, repoSlug, query, limit = 25, start, state = "OPEN" }) => ({
|
|
60
|
+
projectKey,
|
|
61
|
+
repoSlug,
|
|
62
|
+
limit,
|
|
63
|
+
start,
|
|
64
|
+
state: query ?? state
|
|
65
|
+
})
|
|
66
|
+
},
|
|
67
|
+
github: {
|
|
68
|
+
mode: "structured-operation",
|
|
69
|
+
operation: "issues",
|
|
70
|
+
description: "GitHub Enterprise repository issue search/list. Requires owner and repo.",
|
|
71
|
+
required: ["owner", "repo"],
|
|
72
|
+
buildParams: ({ owner, repo, query, state = "open", per_page = 25 }) => ({
|
|
73
|
+
owner,
|
|
74
|
+
repo,
|
|
75
|
+
state: query ?? state,
|
|
76
|
+
per_page
|
|
77
|
+
})
|
|
78
|
+
},
|
|
79
|
+
dashboard: {
|
|
80
|
+
mode: "structured-operation",
|
|
81
|
+
operation: "discover",
|
|
82
|
+
description: "Dashboard discover read."
|
|
83
|
+
},
|
|
84
|
+
slack: {
|
|
85
|
+
mode: "specialized-function",
|
|
86
|
+
description: "Slack keyword search via browser SSO. Supports messages, files, all, and autocomplete scopes.",
|
|
87
|
+
async execute(input, options) {
|
|
88
|
+
const {
|
|
89
|
+
searchSlackAll,
|
|
90
|
+
searchSlackAutocomplete,
|
|
91
|
+
searchSlackFiles,
|
|
92
|
+
searchSlackMessages
|
|
93
|
+
} = await import("../../access-okta-slack/src/slackSearch.mjs");
|
|
94
|
+
const commonOptions = {
|
|
95
|
+
count: input.count,
|
|
96
|
+
sort: input.sort,
|
|
97
|
+
sortDir: input.sortDir,
|
|
98
|
+
highlight: input.highlight,
|
|
99
|
+
...options
|
|
100
|
+
};
|
|
101
|
+
const scope = String(input.scope || "messages").toLowerCase();
|
|
102
|
+
if (scope === "all") return searchSlackAll(input.query, commonOptions);
|
|
103
|
+
if (scope === "files") return searchSlackFiles(input.query, commonOptions);
|
|
104
|
+
if (scope === "autocomplete") return searchSlackAutocomplete(input.query, { ...commonOptions, types: input.types });
|
|
105
|
+
return searchSlackMessages(input.query, commonOptions);
|
|
106
|
+
}
|
|
107
|
+
},
|
|
108
|
+
"service-hub": {
|
|
109
|
+
mode: "specialized-function",
|
|
110
|
+
description: "Service Hub (ServiceNow) table search via sysparm_query.",
|
|
111
|
+
async execute(input, options) {
|
|
112
|
+
const { searchServiceHubTable } = await import("../../access-okta-workday-service-hub/src/serviceHubSessionRead.mjs");
|
|
113
|
+
if (!input.query) throw new Error("query is required for service-hub search.");
|
|
114
|
+
return searchServiceHubTable(input.table ?? "incident", input.query, { ...input, ...options });
|
|
115
|
+
}
|
|
116
|
+
},
|
|
117
|
+
collibra: {
|
|
118
|
+
mode: "specialized-function",
|
|
119
|
+
description: "Collibra asset name search.",
|
|
120
|
+
async execute(input, options) {
|
|
121
|
+
const { searchCollibraAssets } = await import(
|
|
122
|
+
"../../access-okta-collibra-data-intelligence-platform/src/collibraSessionRead.mjs"
|
|
123
|
+
);
|
|
124
|
+
if (!input.query) throw new Error("query is required for collibra search.");
|
|
125
|
+
return searchCollibraAssets(input.query, { ...input, ...options });
|
|
126
|
+
}
|
|
127
|
+
},
|
|
128
|
+
snyk: {
|
|
129
|
+
mode: "specialized-function",
|
|
130
|
+
description: "Snyk project search within an org slug.",
|
|
131
|
+
required: ["orgSlug"],
|
|
132
|
+
async execute(input, options) {
|
|
133
|
+
const { listSnykOrganizations, readSnykCurrentUser, searchSnykProjects } = await import(
|
|
134
|
+
"../../access-okta-snyk/src/snykSessionRead.mjs"
|
|
135
|
+
);
|
|
136
|
+
const scope = String(input.scope || "projects").toLowerCase();
|
|
137
|
+
if (scope === "me") return readSnykCurrentUser({ ...input, ...options });
|
|
138
|
+
if (scope === "orgs") return listSnykOrganizations({ ...input, ...options });
|
|
139
|
+
return searchSnykProjects(input.query ?? "", {
|
|
140
|
+
...input,
|
|
141
|
+
...options,
|
|
142
|
+
orgSlug: input.orgSlug ?? input.org
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
},
|
|
146
|
+
"google-drive": {
|
|
147
|
+
mode: "specialized-function",
|
|
148
|
+
description: "Google Drive file search via Drive v3 q= query.",
|
|
149
|
+
async execute(input, options) {
|
|
150
|
+
const { searchGoogleDriveFiles } = await import(
|
|
151
|
+
"../../access-okta-workday-google-apps-drive/src/googleDriveSessionRead.mjs"
|
|
152
|
+
);
|
|
153
|
+
if (!input.query && !input.mimeType && !input.folderId) {
|
|
154
|
+
throw new Error("Provide query, mimeType, or folderId for google-drive search.");
|
|
155
|
+
}
|
|
156
|
+
return searchGoogleDriveFiles(input, { ...input, ...options });
|
|
157
|
+
}
|
|
158
|
+
},
|
|
159
|
+
mixpanel: {
|
|
160
|
+
mode: "specialized-function",
|
|
161
|
+
description: "Mixpanel report search or workspace list.",
|
|
162
|
+
async execute(input, options) {
|
|
163
|
+
const { readMixpanelWorkspaces, searchMixpanelReports } = await import(
|
|
164
|
+
"../../access-okta-mixpanel/src/mixpanelSessionRead.mjs"
|
|
165
|
+
);
|
|
166
|
+
const scope = String(input.scope || "reports").toLowerCase();
|
|
167
|
+
if (scope === "workspaces") return readMixpanelWorkspaces({ ...input, ...options });
|
|
168
|
+
if (!input.query) throw new Error("query is required for mixpanel report search.");
|
|
169
|
+
return searchMixpanelReports(input.query, { ...input, ...options });
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
const READ_STRATEGIES = {
|
|
175
|
+
slack: {
|
|
176
|
+
mode: "specialized-function",
|
|
177
|
+
description: "Slack read scopes: ai-capabilities, bot-history, bot-thread.",
|
|
178
|
+
async execute(input, options) {
|
|
179
|
+
const scope = String(input.scope || "ai-capabilities").toLowerCase();
|
|
180
|
+
if (scope === "bot-history") {
|
|
181
|
+
const { readSlackbotConversations } = await import("../../access-okta-slack/src/slackBotRead.mjs");
|
|
182
|
+
return readSlackbotConversations({ limit: input.limit, ...options });
|
|
183
|
+
}
|
|
184
|
+
if (scope === "bot-thread") {
|
|
185
|
+
const { readSlackbotThread } = await import("../../access-okta-slack/src/slackBotRead.mjs");
|
|
186
|
+
if (!input.threadTs) throw new Error("threadTs is required for slack bot-thread read.");
|
|
187
|
+
return readSlackbotThread(input.threadTs, options);
|
|
188
|
+
}
|
|
189
|
+
const { getSlackAiCapabilities } = await import("../../access-okta-slack/src/slackSearch.mjs");
|
|
190
|
+
return getSlackAiCapabilities(options);
|
|
191
|
+
}
|
|
192
|
+
},
|
|
193
|
+
sana: {
|
|
194
|
+
mode: "specialized-function",
|
|
195
|
+
description: "Sana browser-session GET read. Does not send chatbot messages.",
|
|
196
|
+
async execute(input, options) {
|
|
197
|
+
const { loadSanaSession, sanaReadGet } = await import("../../access-okta-sana/src/sanaSessionRead.mjs");
|
|
198
|
+
const session = await loadSanaSession(options);
|
|
199
|
+
return sanaReadGet(session, input.restPath || input.path || "/", {
|
|
200
|
+
followRedirects: input.followRedirects,
|
|
201
|
+
...options
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
},
|
|
205
|
+
"service-hub": {
|
|
206
|
+
mode: "specialized-function",
|
|
207
|
+
description: "Service Hub record read by table + sys_id.",
|
|
208
|
+
async execute(input, options) {
|
|
209
|
+
const { readServiceHubRecord } = await import("../../access-okta-workday-service-hub/src/serviceHubSessionRead.mjs");
|
|
210
|
+
if (!input.table || !input.sysId) throw new Error("table and sysId are required for service-hub read.");
|
|
211
|
+
return readServiceHubRecord(input.table, input.sysId, { ...input, ...options });
|
|
212
|
+
}
|
|
213
|
+
},
|
|
214
|
+
collibra: {
|
|
215
|
+
mode: "specialized-function",
|
|
216
|
+
description: "Collibra asset read or communities list.",
|
|
217
|
+
async execute(input, options) {
|
|
218
|
+
const { listCollibraCommunities, readCollibraAsset } = await import(
|
|
219
|
+
"../../access-okta-collibra-data-intelligence-platform/src/collibraSessionRead.mjs"
|
|
220
|
+
);
|
|
221
|
+
if (input.scope === "communities") return listCollibraCommunities({ ...input, ...options });
|
|
222
|
+
if (!input.assetId) throw new Error("assetId is required for collibra asset read.");
|
|
223
|
+
return readCollibraAsset(input.assetId, { ...input, ...options });
|
|
224
|
+
}
|
|
225
|
+
},
|
|
226
|
+
snyk: {
|
|
227
|
+
mode: "specialized-function",
|
|
228
|
+
description: "Snyk project read by org slug + project id.",
|
|
229
|
+
async execute(input, options) {
|
|
230
|
+
const { readSnykProject } = await import("../../access-okta-snyk/src/snykSessionRead.mjs");
|
|
231
|
+
if (!input.orgSlug && !input.org) throw new Error("orgSlug is required for snyk project read.");
|
|
232
|
+
if (!input.projectId) throw new Error("projectId is required for snyk project read.");
|
|
233
|
+
return readSnykProject(input.orgSlug ?? input.org, input.projectId, { ...input, ...options });
|
|
234
|
+
}
|
|
235
|
+
},
|
|
236
|
+
"google-drive": {
|
|
237
|
+
mode: "specialized-function",
|
|
238
|
+
description: "Google Drive file read by fileId.",
|
|
239
|
+
async execute(input, options) {
|
|
240
|
+
const { readGoogleDriveFile } = await import("../../access-okta-workday-google-apps-drive/src/googleDriveSessionRead.mjs");
|
|
241
|
+
if (!input.fileId) throw new Error("fileId is required for google-drive file read.");
|
|
242
|
+
return readGoogleDriveFile(input.fileId, { ...input, ...options });
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
};
|
|
246
|
+
|
|
247
|
+
function defaultReadPath(service) {
|
|
248
|
+
return service.readAccess?.probePath ?? service.readAccess?.restPathPrefix ?? "/";
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
function serviceSearchCapability(service) {
|
|
252
|
+
const strategy = SEARCH_STRATEGIES[service.id];
|
|
253
|
+
if (strategy) {
|
|
254
|
+
return {
|
|
255
|
+
mode: strategy.mode,
|
|
256
|
+
operation: strategy.operation,
|
|
257
|
+
required: strategy.required ?? [],
|
|
258
|
+
description: strategy.description
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
if (service.readAccess?.oktaAppName) {
|
|
262
|
+
return {
|
|
263
|
+
mode: "generic-okta-get",
|
|
264
|
+
required: ["searchPath"],
|
|
265
|
+
description: "No stable search API is known. Provide an app-specific GET searchPath and query parameters."
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
if (service.readAccess?.mode === "cookie-http" || service.readAccess?.mode === "public-http") {
|
|
269
|
+
return {
|
|
270
|
+
mode: "generic-get",
|
|
271
|
+
required: ["searchPath"],
|
|
272
|
+
description: "No structured search operation is known. Provide a service-specific GET searchPath and query parameters."
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
return {
|
|
276
|
+
mode: service.readAccess?.mode ?? "unsupported",
|
|
277
|
+
required: [],
|
|
278
|
+
description: service.readAccess?.note ?? "Search must use the service-specific read-only workflow or command pack."
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
function packageDirFromExtension(extensionName) {
|
|
283
|
+
const prefix = "@nuvlore/extension-";
|
|
284
|
+
if (!String(extensionName).startsWith(prefix)) return "";
|
|
285
|
+
return join(EXTENSIONS_DIR, String(extensionName).slice(prefix.length));
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
function classifyTool(toolName) {
|
|
289
|
+
if (/(search|query|discover)/i.test(toolName)) return "search";
|
|
290
|
+
if (/(ask|chat)/i.test(toolName)) return "chatbot";
|
|
291
|
+
if (/(sync|export)/i.test(toolName)) return "sync";
|
|
292
|
+
if (/(verify|status|access)/i.test(toolName)) return "verify";
|
|
293
|
+
return "read";
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
function readToolMetadata(filePath) {
|
|
297
|
+
const text = readFileSync(filePath, "utf8");
|
|
298
|
+
const name = text.match(/\bname:\s*["']([^"']+)["']/)?.[1];
|
|
299
|
+
if (!name) return null;
|
|
300
|
+
const description = text.match(/\bdescription:\s*["']([^"']+)["']/)?.[1] ?? "";
|
|
301
|
+
return {
|
|
302
|
+
name,
|
|
303
|
+
description,
|
|
304
|
+
category: classifyTool(name),
|
|
305
|
+
file: filePath.slice(EXTENSIONS_DIR.length + 1)
|
|
306
|
+
};
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
export function listServiceSpecializedTools(service) {
|
|
310
|
+
const packageDir = packageDirFromExtension(service.extension);
|
|
311
|
+
const toolsDir = packageDir ? join(packageDir, "tools") : "";
|
|
312
|
+
if (!toolsDir || !existsSync(toolsDir)) return [];
|
|
313
|
+
return readdirSync(toolsDir)
|
|
314
|
+
.filter((fileName) => fileName.endsWith(".mjs"))
|
|
315
|
+
.map((fileName) => readToolMetadata(join(toolsDir, fileName)))
|
|
316
|
+
.filter(Boolean)
|
|
317
|
+
.sort((left, right) => left.name.localeCompare(right.name));
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
export function listServiceReadSearchCapabilities() {
|
|
321
|
+
return listWorkdayServices().map((service) => ({
|
|
322
|
+
service: service.id,
|
|
323
|
+
label: service.label,
|
|
324
|
+
extension: service.extension,
|
|
325
|
+
readOnly: service.readAccess?.readOnly !== false,
|
|
326
|
+
read: {
|
|
327
|
+
mode: service.readAccess?.mode ?? "unsupported",
|
|
328
|
+
defaultPath: defaultReadPath(service),
|
|
329
|
+
oktaAppName: service.readAccess?.oktaAppName,
|
|
330
|
+
specialized: READ_STRATEGIES[service.id]
|
|
331
|
+
? {
|
|
332
|
+
mode: READ_STRATEGIES[service.id].mode,
|
|
333
|
+
description: READ_STRATEGIES[service.id].description
|
|
334
|
+
}
|
|
335
|
+
: undefined
|
|
336
|
+
},
|
|
337
|
+
search: serviceSearchCapability(service),
|
|
338
|
+
specializedTools: listServiceSpecializedTools(service)
|
|
339
|
+
})).map((capability) => {
|
|
340
|
+
const searchTools = capability.specializedTools.filter((tool) => tool.category === "search");
|
|
341
|
+
if (searchTools.length && String(capability.search.mode).startsWith("generic")) {
|
|
342
|
+
return {
|
|
343
|
+
...capability,
|
|
344
|
+
search: {
|
|
345
|
+
mode: "specialized-tools",
|
|
346
|
+
required: [],
|
|
347
|
+
tools: searchTools.map((tool) => tool.name),
|
|
348
|
+
description: "Use the service-specific search/discover tools listed in specializedTools."
|
|
349
|
+
}
|
|
350
|
+
};
|
|
351
|
+
}
|
|
352
|
+
return capability;
|
|
353
|
+
});
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
export async function readAnyService(serviceId, input = {}, options = {}) {
|
|
357
|
+
const service = getWorkdayService(serviceId);
|
|
358
|
+
const strategy = READ_STRATEGIES[service.id];
|
|
359
|
+
if (strategy) {
|
|
360
|
+
return strategy.execute(input, options);
|
|
361
|
+
}
|
|
362
|
+
const restPath = input.restPath || input.path || defaultReadPath(service);
|
|
363
|
+
return extensionReadGet(service.id, {
|
|
364
|
+
...input,
|
|
365
|
+
restPath
|
|
366
|
+
}, options);
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
export async function searchAnyService(serviceId, input = {}, options = {}) {
|
|
370
|
+
const service = getWorkdayService(serviceId);
|
|
371
|
+
const strategy = SEARCH_STRATEGIES[service.id];
|
|
372
|
+
if (strategy) {
|
|
373
|
+
if (strategy.execute) {
|
|
374
|
+
return strategy.execute(input, options);
|
|
375
|
+
}
|
|
376
|
+
const params = strategy.buildParams ? strategy.buildParams(input) : input;
|
|
377
|
+
getServiceOperation(service.id, strategy.operation);
|
|
378
|
+
buildServiceOperationInput(service.id, strategy.operation, params);
|
|
379
|
+
return readServiceOperation(service.id, strategy.operation, params, options);
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
const searchPath = String(input.searchPath || input.restPath || input.path || "").trim();
|
|
383
|
+
if (!searchPath) {
|
|
384
|
+
const capability = serviceSearchCapability(service);
|
|
385
|
+
throw new Error(
|
|
386
|
+
`No structured search operation is known for ${service.id}. Provide searchPath for a read-only GET search. Capability: ${capability.description}`
|
|
387
|
+
);
|
|
388
|
+
}
|
|
389
|
+
return extensionReadGet(service.id, {
|
|
390
|
+
restPath: searchPath,
|
|
391
|
+
query: input.query,
|
|
392
|
+
baseUrl: input.baseUrl,
|
|
393
|
+
allowCookieFallback: input.allowCookieFallback
|
|
394
|
+
}, options);
|
|
395
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { ssoReadGet, ssoReadHtml, verifySsoAccess } from "./ssoHttpRead.mjs";
|
|
2
|
+
import { syncOktaAppCookies } from "./sessionManager.mjs";
|
|
3
|
+
import { getOktaApp } from "./oktaAppCatalog.mjs";
|
|
4
|
+
import { oktaAppHttpRead } from "./oktaAppRead.mjs";
|
|
5
|
+
|
|
6
|
+
export async function readJiraMyself(options = {}) {
|
|
7
|
+
return ssoReadGet("jira", { restPath: "/rest/api/latest/myself" }, options);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export async function readJiraProjects(options = {}) {
|
|
11
|
+
return ssoReadGet("jira", { restPath: "/rest/api/latest/project" }, options);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export async function readJiraSearch(jql, options = {}) {
|
|
15
|
+
const query = { jql: String(jql || "order by updated DESC"), maxResults: options.maxResults ?? 10 };
|
|
16
|
+
return ssoReadGet("jira", { restPath: "/rest/api/latest/search", query }, options);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export async function readJiraIssue(issueKey, options = {}) {
|
|
20
|
+
const key = String(issueKey || "").trim();
|
|
21
|
+
if (!key) throw new Error("issueKey is required.");
|
|
22
|
+
return ssoReadGet("jira", { restPath: `/rest/api/latest/issue/${encodeURIComponent(key)}` }, options);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export async function readConfluenceUser(options = {}) {
|
|
26
|
+
return ssoReadGet("confluence", { restPath: "/rest/api/user/current" }, options);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export async function readConfluenceSpaces(options = {}) {
|
|
30
|
+
return ssoReadGet("confluence", { restPath: "/rest/api/space", query: { limit: options.limit ?? 25 } }, options);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export async function readBambooInfo(options = {}) {
|
|
34
|
+
return ssoReadGet("bamboo", { restPath: "/rest/api/latest/info" }, options);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export async function readBambooPlans(options = {}) {
|
|
38
|
+
return ssoReadGet("bamboo", { restPath: "/rest/api/latest/plan", query: { maxResults: options.limit ?? 25 } }, options);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export async function readGithubProfile(options = {}) {
|
|
42
|
+
return ssoReadHtml("github", "/settings/profile", { extract: "github-profile" }, options);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export async function readBitbucketSession(options = {}) {
|
|
46
|
+
return ssoReadHtml("bitbucket", "/login", { extract: "atlassian-session", followRedirects: true }, options);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export async function readPharosHealth(options = {}) {
|
|
50
|
+
return ssoReadGet("pharos", { restPath: "/api/health" }, options);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export async function readTeamCityLoginPage(options = {}) {
|
|
54
|
+
return ssoReadHtml("teamcity", "/login.html", { extract: "generic" }, options);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export async function readPagerDutyMe(options = {}) {
|
|
58
|
+
return ssoReadGet("pagerduty", { restPath: "/api/v2/users/me" }, options);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export async function readRepositoryPing(options = {}) {
|
|
62
|
+
return ssoReadGet("repository", { restPath: "/artifactory/api/system/ping" }, options);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export async function readOktaApp(appName, input = {}, options = {}) {
|
|
66
|
+
await syncOktaAppCookies(appName, options);
|
|
67
|
+
const app = getOktaApp(appName);
|
|
68
|
+
if (app.serviceId && !input.forceCookie) {
|
|
69
|
+
const route = SERVICE_READ_DEFAULTS[app.serviceId];
|
|
70
|
+
if (input.useDefault && route) {
|
|
71
|
+
return route(input, options);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return oktaAppHttpRead(appName, input, options);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const SERVICE_READ_DEFAULTS = {
|
|
78
|
+
jira: (_input, options) => readJiraMyself(options),
|
|
79
|
+
confluence: (_input, options) => readConfluenceUser(options),
|
|
80
|
+
bamboo: (_input, options) => readBambooInfo(options),
|
|
81
|
+
github: (_input, options) => readGithubProfile(options),
|
|
82
|
+
bitbucket: (_input, options) => readBitbucketSession(options),
|
|
83
|
+
pharos: (_input, options) => readPharosHealth(options),
|
|
84
|
+
pagerduty: (_input, options) => readPagerDutyMe(options),
|
|
85
|
+
repository: (_input, options) => readRepositoryPing(options)
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
export async function readServiceDefault(serviceId, options = {}) {
|
|
89
|
+
const reader = SERVICE_READ_DEFAULTS[serviceId];
|
|
90
|
+
if (!reader) {
|
|
91
|
+
return verifySsoAccess(serviceId, options);
|
|
92
|
+
}
|
|
93
|
+
return reader({}, options);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export function listServiceReadCapabilities() {
|
|
97
|
+
return {
|
|
98
|
+
jira: ["myself", "projects", "search", "issue", "project", "project_versions", "user_assignable_search"],
|
|
99
|
+
confluence: ["user", "spaces", "search", "content", "space", "space_content"],
|
|
100
|
+
bamboo: ["info", "plans", "plan", "plan_results", "result", "latest_result"],
|
|
101
|
+
bitbucket: ["session", "projects", "repos", "repo", "pull_request", "pull_requests", "commits"],
|
|
102
|
+
github: ["profile", "repo", "pull", "issues", "commits"],
|
|
103
|
+
pharos: ["health", "search", "datasources"],
|
|
104
|
+
teamcity: ["login-page", "projects", "project", "builds", "build"],
|
|
105
|
+
pagerduty: ["me", "incidents", "incident", "oncalls", "services"],
|
|
106
|
+
repository: ["ping", "artifact", "search_gavc", "system_ping"],
|
|
107
|
+
dashboard: ["discover", "path"]
|
|
108
|
+
};
|
|
109
|
+
}
|