chore: import upstream snapshot with attribution
Publish CLI Package / publish-npm (push) Waiting to run
Publish Python SDK / publish-pypi (push) Waiting to run
Publish TypeScript SDK / publish-npm (push) Waiting to run
CI / Migrate Dev DB (push) Has been skipped
CI / Detect Version (push) Has been cancelled
CI / Migrate DB (push) Has been cancelled
CI / Build Dev ECR (./docker/app.Dockerfile, ECR_APP) (push) Has been cancelled
CI / Build Dev ECR (./docker/db.Dockerfile, ECR_MIGRATIONS) (push) Has been cancelled
CI / Build Dev ECR (./docker/pii.Dockerfile, ECR_PII) (push) Has been cancelled
CI / Build Dev ECR (./docker/realtime.Dockerfile, ECR_REALTIME) (push) Has been cancelled
CI / Deploy Trigger.dev (Dev) (push) Has been cancelled
CI / Build AMD64 (./docker/app.Dockerfile, ECR_APP, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build AMD64 (./docker/db.Dockerfile, ECR_MIGRATIONS, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build AMD64 (./docker/pii.Dockerfile, ECR_PII, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build AMD64 (./docker/realtime.Dockerfile, ECR_REALTIME, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/app.Dockerfile, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/db.Dockerfile, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/pii.Dockerfile, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/realtime.Dockerfile, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Check Docs Changes (push) Has been cancelled
CI / Process Docs (push) Has been cancelled
CI / Create GitHub Release (push) Has been cancelled
CI / Test and Build (push) Has been cancelled
Publish CLI Package / publish-npm (push) Waiting to run
Publish Python SDK / publish-pypi (push) Waiting to run
Publish TypeScript SDK / publish-npm (push) Waiting to run
CI / Migrate Dev DB (push) Has been skipped
CI / Detect Version (push) Has been cancelled
CI / Migrate DB (push) Has been cancelled
CI / Build Dev ECR (./docker/app.Dockerfile, ECR_APP) (push) Has been cancelled
CI / Build Dev ECR (./docker/db.Dockerfile, ECR_MIGRATIONS) (push) Has been cancelled
CI / Build Dev ECR (./docker/pii.Dockerfile, ECR_PII) (push) Has been cancelled
CI / Build Dev ECR (./docker/realtime.Dockerfile, ECR_REALTIME) (push) Has been cancelled
CI / Deploy Trigger.dev (Dev) (push) Has been cancelled
CI / Build AMD64 (./docker/app.Dockerfile, ECR_APP, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build AMD64 (./docker/db.Dockerfile, ECR_MIGRATIONS, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build AMD64 (./docker/pii.Dockerfile, ECR_PII, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build AMD64 (./docker/realtime.Dockerfile, ECR_REALTIME, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/app.Dockerfile, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/db.Dockerfile, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/pii.Dockerfile, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/realtime.Dockerfile, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Check Docs Changes (push) Has been cancelled
CI / Process Docs (push) Has been cancelled
CI / Create GitHub Release (push) Has been cancelled
CI / Test and Build (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,132 @@
|
||||
import type { JsmAddCommentParams, JsmAddCommentResponse } from '@/tools/jsm/types'
|
||||
import { USER_OUTPUT_PROPERTIES } from '@/tools/jsm/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const jsmAddCommentTool: ToolConfig<JsmAddCommentParams, JsmAddCommentResponse> = {
|
||||
id: 'jsm_add_comment',
|
||||
name: 'JSM Add Comment',
|
||||
description: 'Add a comment (public or internal) to a service request in Jira Service Management',
|
||||
version: '1.0.0',
|
||||
|
||||
oauth: {
|
||||
required: true,
|
||||
provider: 'jira',
|
||||
},
|
||||
|
||||
params: {
|
||||
accessToken: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'hidden',
|
||||
description: 'OAuth access token for Jira Service Management',
|
||||
},
|
||||
domain: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Your Jira domain (e.g., yourcompany.atlassian.net)',
|
||||
},
|
||||
cloudId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'hidden',
|
||||
description: 'Jira Cloud ID for the instance',
|
||||
},
|
||||
issueIdOrKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Issue ID or key (e.g., SD-123)',
|
||||
},
|
||||
body: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Comment body text',
|
||||
},
|
||||
isPublic: {
|
||||
type: 'boolean',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Whether the comment is public (visible to customer) or internal (true/false)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: '/api/tools/jsm/comment',
|
||||
method: 'POST',
|
||||
headers: () => ({
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
body: (params) => ({
|
||||
domain: params.domain,
|
||||
accessToken: params.accessToken,
|
||||
cloudId: params.cloudId,
|
||||
issueIdOrKey: params.issueIdOrKey,
|
||||
body: params.body,
|
||||
isPublic: params.isPublic,
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const responseText = await response.text()
|
||||
|
||||
if (!responseText) {
|
||||
return {
|
||||
success: false,
|
||||
output: {
|
||||
ts: new Date().toISOString(),
|
||||
issueIdOrKey: '',
|
||||
commentId: '',
|
||||
body: '',
|
||||
isPublic: false,
|
||||
author: null,
|
||||
createdDate: null,
|
||||
success: false,
|
||||
},
|
||||
error: 'Empty response from API',
|
||||
}
|
||||
}
|
||||
|
||||
const data = JSON.parse(responseText)
|
||||
|
||||
if (data.success && data.output) {
|
||||
return data
|
||||
}
|
||||
|
||||
return {
|
||||
success: data.success || false,
|
||||
output: data.output || {
|
||||
ts: new Date().toISOString(),
|
||||
issueIdOrKey: '',
|
||||
commentId: '',
|
||||
body: '',
|
||||
isPublic: false,
|
||||
author: null,
|
||||
createdDate: null,
|
||||
success: false,
|
||||
},
|
||||
error: data.error,
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
ts: { type: 'string', description: 'Timestamp of the operation' },
|
||||
issueIdOrKey: { type: 'string', description: 'Issue ID or key' },
|
||||
commentId: { type: 'string', description: 'Created comment ID' },
|
||||
body: { type: 'string', description: 'Comment body text' },
|
||||
isPublic: { type: 'boolean', description: 'Whether the comment is public' },
|
||||
author: {
|
||||
type: 'object',
|
||||
description: 'Comment author',
|
||||
properties: USER_OUTPUT_PROPERTIES,
|
||||
optional: true,
|
||||
},
|
||||
createdDate: {
|
||||
type: 'json',
|
||||
description: 'Comment creation date with iso8601, friendly, epochMillis',
|
||||
optional: true,
|
||||
},
|
||||
success: { type: 'boolean', description: 'Whether the comment was added successfully' },
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
import type { JsmAddCustomerParams, JsmAddCustomerResponse } from '@/tools/jsm/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const jsmAddCustomerTool: ToolConfig<JsmAddCustomerParams, JsmAddCustomerResponse> = {
|
||||
id: 'jsm_add_customer',
|
||||
name: 'JSM Add Customer',
|
||||
description: 'Add customers to a service desk in Jira Service Management',
|
||||
version: '1.0.0',
|
||||
|
||||
oauth: {
|
||||
required: true,
|
||||
provider: 'jira',
|
||||
},
|
||||
|
||||
params: {
|
||||
accessToken: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'hidden',
|
||||
description: 'OAuth access token for Jira Service Management',
|
||||
},
|
||||
domain: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Your Jira domain (e.g., yourcompany.atlassian.net)',
|
||||
},
|
||||
cloudId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'hidden',
|
||||
description: 'Jira Cloud ID for the instance',
|
||||
},
|
||||
serviceDeskId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Service Desk ID (e.g., "1", "2")',
|
||||
},
|
||||
accountIds: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Comma-separated Atlassian account IDs to add as customers',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: '/api/tools/jsm/customers',
|
||||
method: 'POST',
|
||||
headers: () => ({
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
body: (params) => ({
|
||||
domain: params.domain,
|
||||
accessToken: params.accessToken,
|
||||
cloudId: params.cloudId,
|
||||
serviceDeskId: params.serviceDeskId,
|
||||
accountIds: params.accountIds,
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const responseText = await response.text()
|
||||
|
||||
if (!responseText) {
|
||||
return {
|
||||
success: false,
|
||||
output: {
|
||||
ts: new Date().toISOString(),
|
||||
serviceDeskId: '',
|
||||
success: false,
|
||||
},
|
||||
error: 'Empty response from API',
|
||||
}
|
||||
}
|
||||
|
||||
const data = JSON.parse(responseText)
|
||||
|
||||
if (data.success && data.output) {
|
||||
return data
|
||||
}
|
||||
|
||||
return {
|
||||
success: data.success || false,
|
||||
output: data.output || {
|
||||
ts: new Date().toISOString(),
|
||||
serviceDeskId: '',
|
||||
success: false,
|
||||
},
|
||||
error: data.error,
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
ts: { type: 'string', description: 'Timestamp of the operation' },
|
||||
serviceDeskId: { type: 'string', description: 'Service desk ID' },
|
||||
success: { type: 'boolean', description: 'Whether customers were added successfully' },
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
import type { JsmAddOrganizationParams, JsmAddOrganizationResponse } from '@/tools/jsm/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const jsmAddOrganizationTool: ToolConfig<
|
||||
JsmAddOrganizationParams,
|
||||
JsmAddOrganizationResponse
|
||||
> = {
|
||||
id: 'jsm_add_organization',
|
||||
name: 'JSM Add Organization',
|
||||
description: 'Add an organization to a service desk in Jira Service Management',
|
||||
version: '1.0.0',
|
||||
|
||||
oauth: {
|
||||
required: true,
|
||||
provider: 'jira',
|
||||
},
|
||||
|
||||
params: {
|
||||
accessToken: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'hidden',
|
||||
description: 'OAuth access token for Jira Service Management',
|
||||
},
|
||||
domain: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Your Jira domain (e.g., yourcompany.atlassian.net)',
|
||||
},
|
||||
cloudId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'hidden',
|
||||
description: 'Jira Cloud ID for the instance',
|
||||
},
|
||||
serviceDeskId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Service Desk ID (e.g., "1", "2")',
|
||||
},
|
||||
organizationId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Organization ID to add to the service desk',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: '/api/tools/jsm/organization',
|
||||
method: 'POST',
|
||||
headers: () => ({
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
body: (params) => ({
|
||||
domain: params.domain,
|
||||
accessToken: params.accessToken,
|
||||
cloudId: params.cloudId,
|
||||
serviceDeskId: params.serviceDeskId,
|
||||
organizationId: params.organizationId,
|
||||
action: 'add_to_service_desk',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const responseText = await response.text()
|
||||
|
||||
if (!responseText) {
|
||||
return {
|
||||
success: false,
|
||||
output: {
|
||||
ts: new Date().toISOString(),
|
||||
serviceDeskId: '',
|
||||
organizationId: '',
|
||||
success: false,
|
||||
},
|
||||
error: 'Empty response from API',
|
||||
}
|
||||
}
|
||||
|
||||
const data = JSON.parse(responseText)
|
||||
|
||||
if (data.success && data.output) {
|
||||
return data
|
||||
}
|
||||
|
||||
return {
|
||||
success: data.success || false,
|
||||
output: data.output || {
|
||||
ts: new Date().toISOString(),
|
||||
serviceDeskId: '',
|
||||
organizationId: '',
|
||||
success: false,
|
||||
},
|
||||
error: data.error,
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
ts: { type: 'string', description: 'Timestamp of the operation' },
|
||||
serviceDeskId: { type: 'string', description: 'Service Desk ID' },
|
||||
organizationId: { type: 'string', description: 'Organization ID added' },
|
||||
success: { type: 'boolean', description: 'Whether the operation succeeded' },
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
import type { JsmAddParticipantsParams, JsmAddParticipantsResponse } from '@/tools/jsm/types'
|
||||
import { PARTICIPANT_ITEM_PROPERTIES } from '@/tools/jsm/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const jsmAddParticipantsTool: ToolConfig<
|
||||
JsmAddParticipantsParams,
|
||||
JsmAddParticipantsResponse
|
||||
> = {
|
||||
id: 'jsm_add_participants',
|
||||
name: 'JSM Add Participants',
|
||||
description: 'Add participants to a request in Jira Service Management',
|
||||
version: '1.0.0',
|
||||
|
||||
oauth: {
|
||||
required: true,
|
||||
provider: 'jira',
|
||||
},
|
||||
|
||||
params: {
|
||||
accessToken: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'hidden',
|
||||
description: 'OAuth access token for Jira Service Management',
|
||||
},
|
||||
domain: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Your Jira domain (e.g., yourcompany.atlassian.net)',
|
||||
},
|
||||
cloudId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'hidden',
|
||||
description: 'Jira Cloud ID for the instance',
|
||||
},
|
||||
issueIdOrKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Issue ID or key (e.g., SD-123)',
|
||||
},
|
||||
accountIds: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Comma-separated account IDs to add as participants',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: '/api/tools/jsm/participants',
|
||||
method: 'POST',
|
||||
headers: () => ({
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
body: (params) => ({
|
||||
domain: params.domain,
|
||||
accessToken: params.accessToken,
|
||||
cloudId: params.cloudId,
|
||||
issueIdOrKey: params.issueIdOrKey,
|
||||
accountIds: params.accountIds,
|
||||
action: 'add',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const responseText = await response.text()
|
||||
|
||||
if (!responseText) {
|
||||
return {
|
||||
success: false,
|
||||
output: {
|
||||
ts: new Date().toISOString(),
|
||||
issueIdOrKey: '',
|
||||
participants: [],
|
||||
success: false,
|
||||
},
|
||||
error: 'Empty response from API',
|
||||
}
|
||||
}
|
||||
|
||||
const data = JSON.parse(responseText)
|
||||
|
||||
if (data.success && data.output) {
|
||||
return data
|
||||
}
|
||||
|
||||
return {
|
||||
success: data.success || false,
|
||||
output: data.output || {
|
||||
ts: new Date().toISOString(),
|
||||
issueIdOrKey: '',
|
||||
participants: [],
|
||||
success: false,
|
||||
},
|
||||
error: data.error,
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
ts: { type: 'string', description: 'Timestamp of the operation' },
|
||||
issueIdOrKey: { type: 'string', description: 'Issue ID or key' },
|
||||
participants: {
|
||||
type: 'array',
|
||||
description: 'List of added participants',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: PARTICIPANT_ITEM_PROPERTIES,
|
||||
},
|
||||
},
|
||||
success: { type: 'boolean', description: 'Whether the operation succeeded' },
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,163 @@
|
||||
import type { JsmAnswerApprovalParams, JsmAnswerApprovalResponse } from '@/tools/jsm/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const jsmAnswerApprovalTool: ToolConfig<JsmAnswerApprovalParams, JsmAnswerApprovalResponse> =
|
||||
{
|
||||
id: 'jsm_answer_approval',
|
||||
name: 'JSM Answer Approval',
|
||||
description: 'Approve or decline an approval request in Jira Service Management',
|
||||
version: '1.0.0',
|
||||
|
||||
oauth: {
|
||||
required: true,
|
||||
provider: 'jira',
|
||||
},
|
||||
|
||||
params: {
|
||||
accessToken: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'hidden',
|
||||
description: 'OAuth access token for Jira Service Management',
|
||||
},
|
||||
domain: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Your Jira domain (e.g., yourcompany.atlassian.net)',
|
||||
},
|
||||
cloudId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'hidden',
|
||||
description: 'Jira Cloud ID for the instance',
|
||||
},
|
||||
issueIdOrKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Issue ID or key (e.g., SD-123)',
|
||||
},
|
||||
approvalId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Approval ID to answer',
|
||||
},
|
||||
decision: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Decision: "approve" or "decline"',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: '/api/tools/jsm/approvals',
|
||||
method: 'POST',
|
||||
headers: () => ({
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
body: (params) => ({
|
||||
domain: params.domain,
|
||||
accessToken: params.accessToken,
|
||||
cloudId: params.cloudId,
|
||||
issueIdOrKey: params.issueIdOrKey,
|
||||
approvalId: params.approvalId,
|
||||
decision: params.decision,
|
||||
action: 'answer',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const responseText = await response.text()
|
||||
|
||||
if (!responseText) {
|
||||
return {
|
||||
success: false,
|
||||
output: {
|
||||
ts: new Date().toISOString(),
|
||||
issueIdOrKey: '',
|
||||
approvalId: '',
|
||||
decision: '',
|
||||
finalDecision: null,
|
||||
approvers: null,
|
||||
success: false,
|
||||
},
|
||||
error: 'Empty response from API',
|
||||
}
|
||||
}
|
||||
|
||||
const data = JSON.parse(responseText)
|
||||
|
||||
if (data.success && data.output) {
|
||||
return data
|
||||
}
|
||||
|
||||
return {
|
||||
success: data.success || false,
|
||||
output: data.output || {
|
||||
ts: new Date().toISOString(),
|
||||
issueIdOrKey: '',
|
||||
approvalId: '',
|
||||
decision: '',
|
||||
finalDecision: null,
|
||||
approvers: null,
|
||||
success: false,
|
||||
},
|
||||
error: data.error,
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
ts: { type: 'string', description: 'Timestamp of the operation' },
|
||||
issueIdOrKey: { type: 'string', description: 'Issue ID or key' },
|
||||
approvalId: { type: 'string', description: 'Approval ID' },
|
||||
decision: { type: 'string', description: 'Decision made (approve/decline)' },
|
||||
id: { type: 'string', description: 'Approval ID from response', optional: true },
|
||||
name: { type: 'string', description: 'Approval description', optional: true },
|
||||
finalDecision: {
|
||||
type: 'string',
|
||||
description: 'Final approval decision: pending, approved, or declined',
|
||||
optional: true,
|
||||
},
|
||||
canAnswerApproval: {
|
||||
type: 'boolean',
|
||||
description: 'Whether the current user can still respond',
|
||||
optional: true,
|
||||
},
|
||||
approvers: {
|
||||
type: 'array',
|
||||
description: 'Updated list of approvers with decisions',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
approver: {
|
||||
type: 'object',
|
||||
description: 'Approver user details',
|
||||
properties: {
|
||||
accountId: { type: 'string', description: 'Approver account ID' },
|
||||
displayName: { type: 'string', description: 'Approver display name' },
|
||||
emailAddress: { type: 'string', description: 'Approver email', optional: true },
|
||||
active: {
|
||||
type: 'boolean',
|
||||
description: 'Whether the account is active',
|
||||
optional: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
approverDecision: { type: 'string', description: 'Individual approver decision' },
|
||||
},
|
||||
},
|
||||
optional: true,
|
||||
},
|
||||
createdDate: { type: 'json', description: 'Approval creation date', optional: true },
|
||||
completedDate: { type: 'json', description: 'Approval completion date', optional: true },
|
||||
approval: {
|
||||
type: 'json',
|
||||
description: 'The approval object',
|
||||
optional: true,
|
||||
},
|
||||
success: { type: 'boolean', description: 'Whether the operation succeeded' },
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
import type { JsmAttachFormParams, JsmAttachFormResponse } from '@/tools/jsm/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const jsmAttachFormTool: ToolConfig<JsmAttachFormParams, JsmAttachFormResponse> = {
|
||||
id: 'jsm_attach_form',
|
||||
name: 'JSM Attach Form',
|
||||
description: 'Attach a form template to an existing Jira issue or JSM request',
|
||||
version: '1.0.0',
|
||||
|
||||
oauth: {
|
||||
required: true,
|
||||
provider: 'jira',
|
||||
},
|
||||
|
||||
params: {
|
||||
accessToken: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'hidden',
|
||||
description: 'OAuth access token for Jira Service Management',
|
||||
},
|
||||
domain: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Your Jira domain (e.g., yourcompany.atlassian.net)',
|
||||
},
|
||||
cloudId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'hidden',
|
||||
description: 'Jira Cloud ID for the instance',
|
||||
},
|
||||
issueIdOrKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Issue ID or key to attach the form to (e.g., "SD-123")',
|
||||
},
|
||||
formTemplateId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Form template UUID (from Get Form Templates)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: '/api/tools/jsm/forms/attach',
|
||||
method: 'POST',
|
||||
headers: () => ({
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
body: (params) => ({
|
||||
domain: params.domain,
|
||||
accessToken: params.accessToken,
|
||||
cloudId: params.cloudId,
|
||||
issueIdOrKey: params.issueIdOrKey,
|
||||
formTemplateId: params.formTemplateId,
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const responseText = await response.text()
|
||||
|
||||
if (!responseText) {
|
||||
return {
|
||||
success: false,
|
||||
output: {
|
||||
ts: new Date().toISOString(),
|
||||
issueIdOrKey: '',
|
||||
id: '',
|
||||
name: '',
|
||||
updated: null,
|
||||
submitted: false,
|
||||
lock: false,
|
||||
internal: null,
|
||||
formTemplateId: null,
|
||||
},
|
||||
error: 'Empty response from API',
|
||||
}
|
||||
}
|
||||
|
||||
const data = JSON.parse(responseText)
|
||||
|
||||
if (data.success && data.output) {
|
||||
return data
|
||||
}
|
||||
|
||||
return {
|
||||
success: data.success || false,
|
||||
output: data.output || {
|
||||
ts: new Date().toISOString(),
|
||||
issueIdOrKey: '',
|
||||
id: '',
|
||||
name: '',
|
||||
updated: null,
|
||||
submitted: false,
|
||||
lock: false,
|
||||
internal: null,
|
||||
formTemplateId: null,
|
||||
},
|
||||
error: data.error,
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
ts: { type: 'string', description: 'Timestamp of the operation' },
|
||||
issueIdOrKey: { type: 'string', description: 'Issue ID or key' },
|
||||
id: { type: 'string', description: 'Attached form instance ID (UUID)' },
|
||||
name: { type: 'string', description: 'Form name' },
|
||||
updated: { type: 'string', description: 'Last updated timestamp', optional: true },
|
||||
submitted: { type: 'boolean', description: 'Whether the form has been submitted' },
|
||||
lock: { type: 'boolean', description: 'Whether the form is locked' },
|
||||
internal: { type: 'boolean', description: 'Whether the form is internal only', optional: true },
|
||||
formTemplateId: {
|
||||
type: 'string',
|
||||
description: 'Form template ID',
|
||||
optional: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
import type { JsmCopyFormsParams, JsmCopyFormsResponse } from '@/tools/jsm/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const jsmCopyFormsTool: ToolConfig<JsmCopyFormsParams, JsmCopyFormsResponse> = {
|
||||
id: 'jsm_copy_forms',
|
||||
name: 'JSM Copy Forms',
|
||||
description: 'Copy forms from one Jira issue to another',
|
||||
version: '1.0.0',
|
||||
oauth: { required: true, provider: 'jira' },
|
||||
params: {
|
||||
accessToken: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'hidden',
|
||||
description: 'OAuth access token for Jira Service Management',
|
||||
},
|
||||
domain: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Your Jira domain (e.g., yourcompany.atlassian.net)',
|
||||
},
|
||||
cloudId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'hidden',
|
||||
description: 'Jira Cloud ID for the instance',
|
||||
},
|
||||
sourceIssueIdOrKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Source issue ID or key to copy forms from (e.g., "SD-123")',
|
||||
},
|
||||
targetIssueIdOrKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Target issue ID or key to copy forms to (e.g., "SD-456")',
|
||||
},
|
||||
formIds: {
|
||||
type: 'json',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description:
|
||||
'Optional JSON array of form UUIDs to copy (e.g., ["uuid1", "uuid2"]). If omitted, copies all forms.',
|
||||
},
|
||||
},
|
||||
request: {
|
||||
url: '/api/tools/jsm/forms/copy',
|
||||
method: 'POST',
|
||||
headers: () => ({ 'Content-Type': 'application/json' }),
|
||||
body: (params) => ({
|
||||
domain: params.domain,
|
||||
accessToken: params.accessToken,
|
||||
cloudId: params.cloudId,
|
||||
sourceIssueIdOrKey: params.sourceIssueIdOrKey,
|
||||
targetIssueIdOrKey: params.targetIssueIdOrKey,
|
||||
formIds: params.formIds,
|
||||
}),
|
||||
},
|
||||
transformResponse: async (response: Response) => {
|
||||
const responseText = await response.text()
|
||||
if (!responseText) {
|
||||
return {
|
||||
success: false,
|
||||
output: {
|
||||
ts: new Date().toISOString(),
|
||||
sourceIssueIdOrKey: '',
|
||||
targetIssueIdOrKey: '',
|
||||
copiedForms: [],
|
||||
errors: [],
|
||||
},
|
||||
error: 'Empty response from API',
|
||||
}
|
||||
}
|
||||
const data = JSON.parse(responseText)
|
||||
if (data.success && data.output) return data
|
||||
return {
|
||||
success: data.success || false,
|
||||
output: data.output || {
|
||||
ts: new Date().toISOString(),
|
||||
sourceIssueIdOrKey: '',
|
||||
targetIssueIdOrKey: '',
|
||||
copiedForms: [],
|
||||
errors: [],
|
||||
},
|
||||
error: data.error,
|
||||
}
|
||||
},
|
||||
outputs: {
|
||||
ts: { type: 'string', description: 'Timestamp of the operation' },
|
||||
sourceIssueIdOrKey: { type: 'string', description: 'Source issue ID or key' },
|
||||
targetIssueIdOrKey: { type: 'string', description: 'Target issue ID or key' },
|
||||
copiedForms: { type: 'json', description: 'Array of successfully copied forms' },
|
||||
errors: { type: 'json', description: 'Array of errors encountered during copy' },
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
import type { JsmCreateObjectParams, JsmCreateObjectResponse } from '@/tools/jsm/types'
|
||||
import { ASSET_OBJECT_PROPERTIES } from '@/tools/jsm/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const jsmCreateObjectTool: ToolConfig<JsmCreateObjectParams, JsmCreateObjectResponse> = {
|
||||
id: 'jsm_create_object',
|
||||
name: 'JSM Create Asset Object',
|
||||
description:
|
||||
'Create an Assets (Insight/CMDB) object of a given object type. Attributes use objectTypeAttributeId values from the object type definition.',
|
||||
version: '1.0.0',
|
||||
|
||||
oauth: {
|
||||
required: true,
|
||||
provider: 'jira',
|
||||
},
|
||||
|
||||
params: {
|
||||
accessToken: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'hidden',
|
||||
description: 'OAuth access token for Jira Service Management',
|
||||
},
|
||||
domain: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Your Jira domain (e.g., yourcompany.atlassian.net)',
|
||||
},
|
||||
cloudId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'hidden',
|
||||
description: 'Jira Cloud ID for the instance',
|
||||
},
|
||||
workspaceId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'hidden',
|
||||
description: 'Assets workspace ID (resolved automatically when omitted)',
|
||||
},
|
||||
objectTypeId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'The object type ID to create the object under',
|
||||
},
|
||||
attributes: {
|
||||
type: 'json',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description:
|
||||
'Array of attributes: [{ objectTypeAttributeId, objectAttributeValues: [{ value }] }]',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: '/api/tools/jsm/assets/object/create',
|
||||
method: 'POST',
|
||||
headers: () => ({ 'Content-Type': 'application/json' }),
|
||||
body: (params) => ({
|
||||
domain: params.domain,
|
||||
accessToken: params.accessToken,
|
||||
cloudId: params.cloudId,
|
||||
workspaceId: params.workspaceId,
|
||||
objectTypeId: params.objectTypeId?.trim(),
|
||||
attributes: params.attributes,
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const responseText = await response.text()
|
||||
if (!responseText) {
|
||||
return {
|
||||
success: false,
|
||||
output: { ts: new Date().toISOString(), object: null },
|
||||
error: 'Empty response from API',
|
||||
}
|
||||
}
|
||||
const data = JSON.parse(responseText)
|
||||
if (data.success && data.output) return data
|
||||
return {
|
||||
success: data.success || false,
|
||||
output: data.output || { ts: new Date().toISOString(), object: null },
|
||||
error: data.error,
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
ts: { type: 'string', description: 'Timestamp of the operation' },
|
||||
object: {
|
||||
type: 'json',
|
||||
description: 'The created Assets object',
|
||||
properties: ASSET_OBJECT_PROPERTIES,
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
import type { JsmCreateOrganizationParams, JsmCreateOrganizationResponse } from '@/tools/jsm/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const jsmCreateOrganizationTool: ToolConfig<
|
||||
JsmCreateOrganizationParams,
|
||||
JsmCreateOrganizationResponse
|
||||
> = {
|
||||
id: 'jsm_create_organization',
|
||||
name: 'JSM Create Organization',
|
||||
description: 'Create a new organization in Jira Service Management',
|
||||
version: '1.0.0',
|
||||
|
||||
oauth: {
|
||||
required: true,
|
||||
provider: 'jira',
|
||||
},
|
||||
|
||||
params: {
|
||||
accessToken: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'hidden',
|
||||
description: 'OAuth access token for Jira Service Management',
|
||||
},
|
||||
domain: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Your Jira domain (e.g., yourcompany.atlassian.net)',
|
||||
},
|
||||
cloudId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'hidden',
|
||||
description: 'Jira Cloud ID for the instance',
|
||||
},
|
||||
name: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Name of the organization to create',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: '/api/tools/jsm/organization',
|
||||
method: 'POST',
|
||||
headers: () => ({
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
body: (params) => ({
|
||||
domain: params.domain,
|
||||
accessToken: params.accessToken,
|
||||
cloudId: params.cloudId,
|
||||
name: params.name,
|
||||
action: 'create',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const responseText = await response.text()
|
||||
|
||||
if (!responseText) {
|
||||
return {
|
||||
success: false,
|
||||
output: {
|
||||
ts: new Date().toISOString(),
|
||||
organizationId: '',
|
||||
name: '',
|
||||
success: false,
|
||||
},
|
||||
error: 'Empty response from API',
|
||||
}
|
||||
}
|
||||
|
||||
const data = JSON.parse(responseText)
|
||||
|
||||
if (data.success && data.output) {
|
||||
return data
|
||||
}
|
||||
|
||||
return {
|
||||
success: data.success || false,
|
||||
output: data.output || {
|
||||
ts: new Date().toISOString(),
|
||||
organizationId: '',
|
||||
name: '',
|
||||
success: false,
|
||||
},
|
||||
error: data.error,
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
ts: { type: 'string', description: 'Timestamp of the operation' },
|
||||
organizationId: { type: 'string', description: 'ID of the created organization' },
|
||||
name: { type: 'string', description: 'Name of the created organization' },
|
||||
success: { type: 'boolean', description: 'Whether the operation succeeded' },
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,184 @@
|
||||
import type { JsmCreateRequestParams, JsmCreateRequestResponse } from '@/tools/jsm/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const jsmCreateRequestTool: ToolConfig<JsmCreateRequestParams, JsmCreateRequestResponse> = {
|
||||
id: 'jsm_create_request',
|
||||
name: 'JSM Create Request',
|
||||
description: 'Create a new service request in Jira Service Management',
|
||||
version: '1.0.0',
|
||||
|
||||
oauth: {
|
||||
required: true,
|
||||
provider: 'jira',
|
||||
},
|
||||
|
||||
params: {
|
||||
accessToken: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'hidden',
|
||||
description: 'OAuth access token for Jira Service Management',
|
||||
},
|
||||
domain: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Your Jira domain (e.g., yourcompany.atlassian.net)',
|
||||
},
|
||||
cloudId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'hidden',
|
||||
description: 'Jira Cloud ID for the instance',
|
||||
},
|
||||
serviceDeskId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Service Desk ID (e.g., "1", "2")',
|
||||
},
|
||||
requestTypeId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Request Type ID (e.g., "10", "15")',
|
||||
},
|
||||
summary: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Summary/title for the service request (required unless using Form Answers)',
|
||||
},
|
||||
description: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Description for the service request',
|
||||
},
|
||||
raiseOnBehalfOf: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Account ID of customer to raise request on behalf of',
|
||||
},
|
||||
requestFieldValues: {
|
||||
type: 'json',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description:
|
||||
'Request field values as key-value pairs (overrides summary/description if provided)',
|
||||
},
|
||||
formAnswers: {
|
||||
type: 'json',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description:
|
||||
'Form answers using numeric form question IDs as keys (e.g., {"1": {"text": "Title"}, "4": {"choices": ["5"]}}). Keys are question IDs from the Jira Form, not Jira field names.',
|
||||
},
|
||||
requestParticipants: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Comma-separated account IDs to add as request participants',
|
||||
},
|
||||
channel: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Channel the request originates from (e.g., portal, email)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: '/api/tools/jsm/request',
|
||||
method: 'POST',
|
||||
headers: () => ({
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
body: (params) => ({
|
||||
domain: params.domain,
|
||||
accessToken: params.accessToken,
|
||||
cloudId: params.cloudId,
|
||||
serviceDeskId: params.serviceDeskId,
|
||||
requestTypeId: params.requestTypeId,
|
||||
summary: params.summary,
|
||||
description: params.description,
|
||||
raiseOnBehalfOf: params.raiseOnBehalfOf,
|
||||
requestFieldValues: params.requestFieldValues,
|
||||
formAnswers: params.formAnswers,
|
||||
requestParticipants: params.requestParticipants,
|
||||
channel: params.channel,
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const responseText = await response.text()
|
||||
|
||||
if (!responseText) {
|
||||
return {
|
||||
success: false,
|
||||
output: {
|
||||
ts: new Date().toISOString(),
|
||||
issueId: '',
|
||||
issueKey: '',
|
||||
requestTypeId: '',
|
||||
serviceDeskId: '',
|
||||
createdDate: null,
|
||||
currentStatus: null,
|
||||
reporter: null,
|
||||
success: false,
|
||||
url: '',
|
||||
},
|
||||
error: 'Empty response from API',
|
||||
}
|
||||
}
|
||||
|
||||
const data = JSON.parse(responseText)
|
||||
|
||||
if (data.success && data.output) {
|
||||
return data
|
||||
}
|
||||
|
||||
return {
|
||||
success: data.success || false,
|
||||
output: data.output || {
|
||||
ts: new Date().toISOString(),
|
||||
issueId: '',
|
||||
issueKey: '',
|
||||
requestTypeId: '',
|
||||
serviceDeskId: '',
|
||||
createdDate: null,
|
||||
currentStatus: null,
|
||||
reporter: null,
|
||||
success: false,
|
||||
url: '',
|
||||
},
|
||||
error: data.error,
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
ts: { type: 'string', description: 'Timestamp of the operation' },
|
||||
issueId: { type: 'string', description: 'Created request issue ID' },
|
||||
issueKey: { type: 'string', description: 'Created request issue key (e.g., SD-123)' },
|
||||
requestTypeId: { type: 'string', description: 'Request type ID' },
|
||||
serviceDeskId: { type: 'string', description: 'Service desk ID' },
|
||||
createdDate: {
|
||||
type: 'json',
|
||||
description: 'Creation date with iso8601, friendly, epochMillis',
|
||||
optional: true,
|
||||
},
|
||||
currentStatus: {
|
||||
type: 'json',
|
||||
description: 'Current status with status name and category',
|
||||
optional: true,
|
||||
},
|
||||
reporter: {
|
||||
type: 'json',
|
||||
description: 'Reporter user with accountId, displayName, emailAddress',
|
||||
optional: true,
|
||||
},
|
||||
success: { type: 'boolean', description: 'Whether the request was created successfully' },
|
||||
url: { type: 'string', description: 'URL to the created request' },
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
import type { JsmDeleteFormParams, JsmDeleteFormResponse } from '@/tools/jsm/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const jsmDeleteFormTool: ToolConfig<JsmDeleteFormParams, JsmDeleteFormResponse> = {
|
||||
id: 'jsm_delete_form',
|
||||
name: 'JSM Delete Form',
|
||||
description: 'Remove a form from a Jira issue or JSM request',
|
||||
version: '1.0.0',
|
||||
oauth: { required: true, provider: 'jira' },
|
||||
params: {
|
||||
accessToken: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'hidden',
|
||||
description: 'OAuth access token for Jira Service Management',
|
||||
},
|
||||
domain: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Your Jira domain (e.g., yourcompany.atlassian.net)',
|
||||
},
|
||||
cloudId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'hidden',
|
||||
description: 'Jira Cloud ID for the instance',
|
||||
},
|
||||
issueIdOrKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Issue ID or key (e.g., "SD-123")',
|
||||
},
|
||||
formId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Form instance UUID to delete',
|
||||
},
|
||||
},
|
||||
request: {
|
||||
url: '/api/tools/jsm/forms/delete',
|
||||
method: 'POST',
|
||||
headers: () => ({ 'Content-Type': 'application/json' }),
|
||||
body: (params) => ({
|
||||
domain: params.domain,
|
||||
accessToken: params.accessToken,
|
||||
cloudId: params.cloudId,
|
||||
issueIdOrKey: params.issueIdOrKey,
|
||||
formId: params.formId,
|
||||
}),
|
||||
},
|
||||
transformResponse: async (response: Response) => {
|
||||
const responseText = await response.text()
|
||||
if (!responseText) {
|
||||
return {
|
||||
success: false,
|
||||
output: { ts: new Date().toISOString(), issueIdOrKey: '', formId: '', deleted: false },
|
||||
error: 'Empty response from API',
|
||||
}
|
||||
}
|
||||
const data = JSON.parse(responseText)
|
||||
if (data.success && data.output) return data
|
||||
return {
|
||||
success: data.success || false,
|
||||
output: data.output || {
|
||||
ts: new Date().toISOString(),
|
||||
issueIdOrKey: '',
|
||||
formId: '',
|
||||
deleted: false,
|
||||
},
|
||||
error: data.error,
|
||||
}
|
||||
},
|
||||
outputs: {
|
||||
ts: { type: 'string', description: 'Timestamp of the operation' },
|
||||
issueIdOrKey: { type: 'string', description: 'Issue ID or key' },
|
||||
formId: { type: 'string', description: 'Deleted form instance UUID' },
|
||||
deleted: { type: 'boolean', description: 'Whether the form was successfully deleted' },
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
import type { JsmDeleteObjectParams, JsmDeleteObjectResponse } from '@/tools/jsm/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const jsmDeleteObjectTool: ToolConfig<JsmDeleteObjectParams, JsmDeleteObjectResponse> = {
|
||||
id: 'jsm_delete_object',
|
||||
name: 'JSM Delete Asset Object',
|
||||
description: 'Delete an Assets (Insight/CMDB) object by ID',
|
||||
version: '1.0.0',
|
||||
|
||||
oauth: {
|
||||
required: true,
|
||||
provider: 'jira',
|
||||
},
|
||||
|
||||
params: {
|
||||
accessToken: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'hidden',
|
||||
description: 'OAuth access token for Jira Service Management',
|
||||
},
|
||||
domain: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Your Jira domain (e.g., yourcompany.atlassian.net)',
|
||||
},
|
||||
cloudId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'hidden',
|
||||
description: 'Jira Cloud ID for the instance',
|
||||
},
|
||||
workspaceId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'hidden',
|
||||
description: 'Assets workspace ID (resolved automatically when omitted)',
|
||||
},
|
||||
objectId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'The Assets object ID to delete',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: '/api/tools/jsm/assets/object/delete',
|
||||
method: 'POST',
|
||||
headers: () => ({ 'Content-Type': 'application/json' }),
|
||||
body: (params) => ({
|
||||
domain: params.domain,
|
||||
accessToken: params.accessToken,
|
||||
cloudId: params.cloudId,
|
||||
workspaceId: params.workspaceId,
|
||||
objectId: params.objectId?.trim(),
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const responseText = await response.text()
|
||||
if (!responseText) {
|
||||
return {
|
||||
success: false,
|
||||
output: { ts: new Date().toISOString(), objectId: '', deleted: false },
|
||||
error: 'Empty response from API',
|
||||
}
|
||||
}
|
||||
const data = JSON.parse(responseText)
|
||||
if (data.success && data.output) return data
|
||||
return {
|
||||
success: data.success || false,
|
||||
output: data.output || { ts: new Date().toISOString(), objectId: '', deleted: false },
|
||||
error: data.error,
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
ts: { type: 'string', description: 'Timestamp of the operation' },
|
||||
objectId: { type: 'string', description: 'The deleted object ID' },
|
||||
deleted: { type: 'boolean', description: 'Whether the object was deleted' },
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
import type { JsmExternaliseFormParams, JsmExternaliseFormResponse } from '@/tools/jsm/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const jsmExternaliseFormTool: ToolConfig<
|
||||
JsmExternaliseFormParams,
|
||||
JsmExternaliseFormResponse
|
||||
> = {
|
||||
id: 'jsm_externalise_form',
|
||||
name: 'JSM Externalise Form',
|
||||
description: 'Make a form visible to customers on a Jira issue or JSM request',
|
||||
version: '1.0.0',
|
||||
oauth: { required: true, provider: 'jira' },
|
||||
params: {
|
||||
accessToken: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'hidden',
|
||||
description: 'OAuth access token for Jira Service Management',
|
||||
},
|
||||
domain: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Your Jira domain (e.g., yourcompany.atlassian.net)',
|
||||
},
|
||||
cloudId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'hidden',
|
||||
description: 'Jira Cloud ID for the instance',
|
||||
},
|
||||
issueIdOrKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Issue ID or key (e.g., "SD-123")',
|
||||
},
|
||||
formId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Form instance UUID',
|
||||
},
|
||||
},
|
||||
request: {
|
||||
url: '/api/tools/jsm/forms/externalise',
|
||||
method: 'POST',
|
||||
headers: () => ({ 'Content-Type': 'application/json' }),
|
||||
body: (params) => ({
|
||||
domain: params.domain,
|
||||
accessToken: params.accessToken,
|
||||
cloudId: params.cloudId,
|
||||
issueIdOrKey: params.issueIdOrKey,
|
||||
formId: params.formId,
|
||||
}),
|
||||
},
|
||||
transformResponse: async (response: Response) => {
|
||||
const responseText = await response.text()
|
||||
if (!responseText) {
|
||||
return {
|
||||
success: false,
|
||||
output: { ts: new Date().toISOString(), issueIdOrKey: '', formId: '', visibility: '' },
|
||||
error: 'Empty response from API',
|
||||
}
|
||||
}
|
||||
const data = JSON.parse(responseText)
|
||||
if (data.success && data.output) return data
|
||||
return {
|
||||
success: data.success || false,
|
||||
output: data.output || {
|
||||
ts: new Date().toISOString(),
|
||||
issueIdOrKey: '',
|
||||
formId: '',
|
||||
visibility: '',
|
||||
},
|
||||
error: data.error,
|
||||
}
|
||||
},
|
||||
outputs: {
|
||||
ts: { type: 'string', description: 'Timestamp of the operation' },
|
||||
issueIdOrKey: { type: 'string', description: 'Issue ID or key' },
|
||||
formId: { type: 'string', description: 'Form instance UUID' },
|
||||
visibility: {
|
||||
type: 'string',
|
||||
description: 'Form visibility after change (internal or external)',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
import type { JsmGetApprovalsParams, JsmGetApprovalsResponse } from '@/tools/jsm/types'
|
||||
import { APPROVAL_ITEM_PROPERTIES } from '@/tools/jsm/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const jsmGetApprovalsTool: ToolConfig<JsmGetApprovalsParams, JsmGetApprovalsResponse> = {
|
||||
id: 'jsm_get_approvals',
|
||||
name: 'JSM Get Approvals',
|
||||
description: 'Get approvals for a request in Jira Service Management',
|
||||
version: '1.0.0',
|
||||
|
||||
oauth: {
|
||||
required: true,
|
||||
provider: 'jira',
|
||||
},
|
||||
|
||||
params: {
|
||||
accessToken: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'hidden',
|
||||
description: 'OAuth access token for Jira Service Management',
|
||||
},
|
||||
domain: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Your Jira domain (e.g., yourcompany.atlassian.net)',
|
||||
},
|
||||
cloudId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'hidden',
|
||||
description: 'Jira Cloud ID for the instance',
|
||||
},
|
||||
issueIdOrKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Issue ID or key (e.g., SD-123)',
|
||||
},
|
||||
start: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Start index for pagination (e.g., 0, 50, 100)',
|
||||
},
|
||||
limit: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Maximum results to return (e.g., 10, 25, 50)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: '/api/tools/jsm/approvals',
|
||||
method: 'POST',
|
||||
headers: () => ({
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
body: (params) => ({
|
||||
domain: params.domain,
|
||||
accessToken: params.accessToken,
|
||||
cloudId: params.cloudId,
|
||||
issueIdOrKey: params.issueIdOrKey,
|
||||
start: params.start,
|
||||
limit: params.limit,
|
||||
action: 'get',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const responseText = await response.text()
|
||||
|
||||
if (!responseText) {
|
||||
return {
|
||||
success: false,
|
||||
output: {
|
||||
ts: new Date().toISOString(),
|
||||
issueIdOrKey: '',
|
||||
approvals: [],
|
||||
total: 0,
|
||||
isLastPage: true,
|
||||
},
|
||||
error: 'Empty response from API',
|
||||
}
|
||||
}
|
||||
|
||||
const data = JSON.parse(responseText)
|
||||
|
||||
if (data.success && data.output) {
|
||||
return data
|
||||
}
|
||||
|
||||
return {
|
||||
success: data.success || false,
|
||||
output: data.output || {
|
||||
ts: new Date().toISOString(),
|
||||
issueIdOrKey: '',
|
||||
approvals: [],
|
||||
total: 0,
|
||||
isLastPage: true,
|
||||
},
|
||||
error: data.error,
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
ts: { type: 'string', description: 'Timestamp of the operation' },
|
||||
issueIdOrKey: { type: 'string', description: 'Issue ID or key' },
|
||||
approvals: {
|
||||
type: 'array',
|
||||
description: 'List of approvals',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: APPROVAL_ITEM_PROPERTIES,
|
||||
},
|
||||
},
|
||||
total: { type: 'number', description: 'Total number of approvals' },
|
||||
isLastPage: { type: 'boolean', description: 'Whether this is the last page' },
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
import type { JsmGetCommentsParams, JsmGetCommentsResponse } from '@/tools/jsm/types'
|
||||
import { COMMENT_ITEM_PROPERTIES } from '@/tools/jsm/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const jsmGetCommentsTool: ToolConfig<JsmGetCommentsParams, JsmGetCommentsResponse> = {
|
||||
id: 'jsm_get_comments',
|
||||
name: 'JSM Get Comments',
|
||||
description: 'Get comments for a service request in Jira Service Management',
|
||||
version: '1.0.0',
|
||||
|
||||
oauth: {
|
||||
required: true,
|
||||
provider: 'jira',
|
||||
},
|
||||
|
||||
params: {
|
||||
accessToken: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'hidden',
|
||||
description: 'OAuth access token for Jira Service Management',
|
||||
},
|
||||
domain: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Your Jira domain (e.g., yourcompany.atlassian.net)',
|
||||
},
|
||||
cloudId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'hidden',
|
||||
description: 'Jira Cloud ID for the instance',
|
||||
},
|
||||
issueIdOrKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Issue ID or key (e.g., SD-123)',
|
||||
},
|
||||
isPublic: {
|
||||
type: 'boolean',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Filter to only public comments (true/false)',
|
||||
},
|
||||
internal: {
|
||||
type: 'boolean',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Filter to only internal comments (true/false)',
|
||||
},
|
||||
expand: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Comma-separated fields to expand: renderedBody, attachment',
|
||||
},
|
||||
start: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Start index for pagination (e.g., 0, 50, 100)',
|
||||
},
|
||||
limit: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Maximum results to return (e.g., 10, 25, 50)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: '/api/tools/jsm/comments',
|
||||
method: 'POST',
|
||||
headers: () => ({
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
body: (params) => ({
|
||||
domain: params.domain,
|
||||
accessToken: params.accessToken,
|
||||
cloudId: params.cloudId,
|
||||
issueIdOrKey: params.issueIdOrKey,
|
||||
isPublic: params.isPublic,
|
||||
internal: params.internal,
|
||||
expand: params.expand,
|
||||
start: params.start,
|
||||
limit: params.limit,
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const responseText = await response.text()
|
||||
|
||||
if (!responseText) {
|
||||
return {
|
||||
success: false,
|
||||
output: {
|
||||
ts: new Date().toISOString(),
|
||||
issueIdOrKey: '',
|
||||
comments: [],
|
||||
total: 0,
|
||||
isLastPage: true,
|
||||
},
|
||||
error: 'Empty response from API',
|
||||
}
|
||||
}
|
||||
|
||||
const data = JSON.parse(responseText)
|
||||
|
||||
if (data.success && data.output) {
|
||||
return data
|
||||
}
|
||||
|
||||
return {
|
||||
success: data.success || false,
|
||||
output: data.output || {
|
||||
ts: new Date().toISOString(),
|
||||
issueIdOrKey: '',
|
||||
comments: [],
|
||||
total: 0,
|
||||
isLastPage: true,
|
||||
},
|
||||
error: data.error,
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
ts: { type: 'string', description: 'Timestamp of the operation' },
|
||||
issueIdOrKey: { type: 'string', description: 'Issue ID or key' },
|
||||
comments: {
|
||||
type: 'array',
|
||||
description: 'List of comments',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: COMMENT_ITEM_PROPERTIES,
|
||||
},
|
||||
},
|
||||
total: { type: 'number', description: 'Total number of comments' },
|
||||
isLastPage: { type: 'boolean', description: 'Whether this is the last page' },
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
import type { JsmGetCustomersParams, JsmGetCustomersResponse } from '@/tools/jsm/types'
|
||||
import { CUSTOMER_ITEM_PROPERTIES } from '@/tools/jsm/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const jsmGetCustomersTool: ToolConfig<JsmGetCustomersParams, JsmGetCustomersResponse> = {
|
||||
id: 'jsm_get_customers',
|
||||
name: 'JSM Get Customers',
|
||||
description: 'Get customers for a service desk in Jira Service Management',
|
||||
version: '1.0.0',
|
||||
|
||||
oauth: {
|
||||
required: true,
|
||||
provider: 'jira',
|
||||
},
|
||||
|
||||
params: {
|
||||
accessToken: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'hidden',
|
||||
description: 'OAuth access token for Jira Service Management',
|
||||
},
|
||||
domain: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Your Jira domain (e.g., yourcompany.atlassian.net)',
|
||||
},
|
||||
cloudId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'hidden',
|
||||
description: 'Jira Cloud ID for the instance',
|
||||
},
|
||||
serviceDeskId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Service Desk ID (e.g., "1", "2")',
|
||||
},
|
||||
query: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Search query to filter customers (e.g., "john", "acme")',
|
||||
},
|
||||
start: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Start index for pagination (e.g., 0, 50, 100)',
|
||||
},
|
||||
limit: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Maximum results to return (e.g., 10, 25, 50)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: '/api/tools/jsm/customers',
|
||||
method: 'POST',
|
||||
headers: () => ({
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
body: (params) => ({
|
||||
domain: params.domain,
|
||||
accessToken: params.accessToken,
|
||||
cloudId: params.cloudId,
|
||||
serviceDeskId: params.serviceDeskId,
|
||||
query: params.query,
|
||||
start: params.start,
|
||||
limit: params.limit,
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const responseText = await response.text()
|
||||
|
||||
if (!responseText) {
|
||||
return {
|
||||
success: false,
|
||||
output: {
|
||||
ts: new Date().toISOString(),
|
||||
customers: [],
|
||||
total: 0,
|
||||
isLastPage: true,
|
||||
},
|
||||
error: 'Empty response from API',
|
||||
}
|
||||
}
|
||||
|
||||
const data = JSON.parse(responseText)
|
||||
|
||||
if (data.success && data.output) {
|
||||
return data
|
||||
}
|
||||
|
||||
return {
|
||||
success: data.success || false,
|
||||
output: data.output || {
|
||||
ts: new Date().toISOString(),
|
||||
customers: [],
|
||||
total: 0,
|
||||
isLastPage: true,
|
||||
},
|
||||
error: data.error,
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
ts: { type: 'string', description: 'Timestamp of the operation' },
|
||||
customers: {
|
||||
type: 'array',
|
||||
description: 'List of customers',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: CUSTOMER_ITEM_PROPERTIES,
|
||||
},
|
||||
},
|
||||
total: { type: 'number', description: 'Total number of customers' },
|
||||
isLastPage: { type: 'boolean', description: 'Whether this is the last page' },
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
import type { JsmGetFormParams, JsmGetFormResponse } from '@/tools/jsm/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const jsmGetFormTool: ToolConfig<JsmGetFormParams, JsmGetFormResponse> = {
|
||||
id: 'jsm_get_form',
|
||||
name: 'JSM Get Form',
|
||||
description: 'Get a single form with full design, state, and answers from a Jira issue',
|
||||
version: '1.0.0',
|
||||
|
||||
oauth: {
|
||||
required: true,
|
||||
provider: 'jira',
|
||||
},
|
||||
|
||||
params: {
|
||||
accessToken: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'hidden',
|
||||
description: 'OAuth access token for Jira Service Management',
|
||||
},
|
||||
domain: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Your Jira domain (e.g., yourcompany.atlassian.net)',
|
||||
},
|
||||
cloudId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'hidden',
|
||||
description: 'Jira Cloud ID for the instance',
|
||||
},
|
||||
issueIdOrKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Issue ID or key (e.g., "SD-123")',
|
||||
},
|
||||
formId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Form instance UUID (from Attach Form or Get Issue Forms)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: '/api/tools/jsm/forms/get',
|
||||
method: 'POST',
|
||||
headers: () => ({
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
body: (params) => ({
|
||||
domain: params.domain,
|
||||
accessToken: params.accessToken,
|
||||
cloudId: params.cloudId,
|
||||
issueIdOrKey: params.issueIdOrKey,
|
||||
formId: params.formId,
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const responseText = await response.text()
|
||||
|
||||
if (!responseText) {
|
||||
return {
|
||||
success: false,
|
||||
output: {
|
||||
ts: new Date().toISOString(),
|
||||
issueIdOrKey: '',
|
||||
formId: '',
|
||||
design: null,
|
||||
state: null,
|
||||
updated: null,
|
||||
},
|
||||
error: 'Empty response from API',
|
||||
}
|
||||
}
|
||||
|
||||
const data = JSON.parse(responseText)
|
||||
|
||||
if (data.success && data.output) {
|
||||
return data
|
||||
}
|
||||
|
||||
return {
|
||||
success: data.success || false,
|
||||
output: data.output || {
|
||||
ts: new Date().toISOString(),
|
||||
issueIdOrKey: '',
|
||||
formId: '',
|
||||
design: null,
|
||||
state: null,
|
||||
updated: null,
|
||||
},
|
||||
error: data.error,
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
ts: { type: 'string', description: 'Timestamp of the operation' },
|
||||
issueIdOrKey: { type: 'string', description: 'Issue ID or key' },
|
||||
formId: { type: 'string', description: 'Form instance UUID' },
|
||||
design: {
|
||||
type: 'json',
|
||||
description: 'Full form design with questions, layout, conditions, sections, settings',
|
||||
optional: true,
|
||||
},
|
||||
state: {
|
||||
type: 'json',
|
||||
description:
|
||||
'Form state with answers map, status (o=open, s=submitted, l=locked), visibility (i=internal, e=external)',
|
||||
optional: true,
|
||||
},
|
||||
updated: {
|
||||
type: 'string',
|
||||
description: 'Last updated timestamp',
|
||||
optional: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
import type { JsmGetFormAnswersParams, JsmGetFormAnswersResponse } from '@/tools/jsm/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const jsmGetFormAnswersTool: ToolConfig<JsmGetFormAnswersParams, JsmGetFormAnswersResponse> =
|
||||
{
|
||||
id: 'jsm_get_form_answers',
|
||||
name: 'JSM Get Form Answers',
|
||||
description: 'Get simplified answers from a form attached to a Jira issue or JSM request',
|
||||
version: '1.0.0',
|
||||
|
||||
oauth: {
|
||||
required: true,
|
||||
provider: 'jira',
|
||||
},
|
||||
|
||||
params: {
|
||||
accessToken: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'hidden',
|
||||
description: 'OAuth access token for Jira Service Management',
|
||||
},
|
||||
domain: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Your Jira domain (e.g., yourcompany.atlassian.net)',
|
||||
},
|
||||
cloudId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'hidden',
|
||||
description: 'Jira Cloud ID for the instance',
|
||||
},
|
||||
issueIdOrKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Issue ID or key (e.g., "SD-123")',
|
||||
},
|
||||
formId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Form instance UUID (from Attach Form or Get Issue Forms)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: '/api/tools/jsm/forms/answers',
|
||||
method: 'POST',
|
||||
headers: () => ({
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
body: (params) => ({
|
||||
domain: params.domain,
|
||||
accessToken: params.accessToken,
|
||||
cloudId: params.cloudId,
|
||||
issueIdOrKey: params.issueIdOrKey,
|
||||
formId: params.formId,
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const responseText = await response.text()
|
||||
|
||||
if (!responseText) {
|
||||
return {
|
||||
success: false,
|
||||
output: {
|
||||
ts: new Date().toISOString(),
|
||||
issueIdOrKey: '',
|
||||
formId: '',
|
||||
answers: null,
|
||||
},
|
||||
error: 'Empty response from API',
|
||||
}
|
||||
}
|
||||
|
||||
const data = JSON.parse(responseText)
|
||||
|
||||
if (data.success && data.output) {
|
||||
return data
|
||||
}
|
||||
|
||||
return {
|
||||
success: data.success || false,
|
||||
output: data.output || {
|
||||
ts: new Date().toISOString(),
|
||||
issueIdOrKey: '',
|
||||
formId: '',
|
||||
answers: null,
|
||||
},
|
||||
error: data.error,
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
ts: { type: 'string', description: 'Timestamp of the operation' },
|
||||
issueIdOrKey: { type: 'string', description: 'Issue ID or key' },
|
||||
formId: { type: 'string', description: 'Form instance UUID' },
|
||||
answers: {
|
||||
type: 'json',
|
||||
description:
|
||||
'Simplified form answers as key-value pairs (question label to answer text/choices)',
|
||||
optional: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
import type { JsmGetFormStructureParams, JsmGetFormStructureResponse } from '@/tools/jsm/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const jsmGetFormStructureTool: ToolConfig<
|
||||
JsmGetFormStructureParams,
|
||||
JsmGetFormStructureResponse
|
||||
> = {
|
||||
id: 'jsm_get_form_structure',
|
||||
name: 'JSM Get Form Structure',
|
||||
description:
|
||||
'Get the full structure of a ProForma/JSM form including all questions, field types, choices, layout, and conditions',
|
||||
version: '1.0.0',
|
||||
|
||||
oauth: {
|
||||
required: true,
|
||||
provider: 'jira',
|
||||
},
|
||||
|
||||
params: {
|
||||
accessToken: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'hidden',
|
||||
description: 'OAuth access token for Jira Service Management',
|
||||
},
|
||||
domain: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Your Jira domain (e.g., yourcompany.atlassian.net)',
|
||||
},
|
||||
cloudId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'hidden',
|
||||
description: 'Jira Cloud ID for the instance',
|
||||
},
|
||||
projectIdOrKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Jira project ID or key (e.g., "10001" or "SD")',
|
||||
},
|
||||
formId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Form ID (UUID from Get Form Templates)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: '/api/tools/jsm/forms/structure',
|
||||
method: 'POST',
|
||||
headers: () => ({
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
body: (params) => ({
|
||||
domain: params.domain,
|
||||
accessToken: params.accessToken,
|
||||
cloudId: params.cloudId,
|
||||
projectIdOrKey: params.projectIdOrKey,
|
||||
formId: params.formId,
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const responseText = await response.text()
|
||||
|
||||
if (!responseText) {
|
||||
return {
|
||||
success: false,
|
||||
output: {
|
||||
ts: new Date().toISOString(),
|
||||
projectIdOrKey: '',
|
||||
formId: '',
|
||||
design: null,
|
||||
updated: null,
|
||||
publish: null,
|
||||
},
|
||||
error: 'Empty response from API',
|
||||
}
|
||||
}
|
||||
|
||||
const data = JSON.parse(responseText)
|
||||
|
||||
if (data.success && data.output) {
|
||||
return data
|
||||
}
|
||||
|
||||
return {
|
||||
success: data.success || false,
|
||||
output: data.output || {
|
||||
ts: new Date().toISOString(),
|
||||
projectIdOrKey: '',
|
||||
formId: '',
|
||||
design: null,
|
||||
updated: null,
|
||||
publish: null,
|
||||
},
|
||||
error: data.error,
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
ts: { type: 'string', description: 'Timestamp of the operation' },
|
||||
projectIdOrKey: { type: 'string', description: 'Project ID or key' },
|
||||
formId: { type: 'string', description: 'Form ID' },
|
||||
design: {
|
||||
type: 'json',
|
||||
description:
|
||||
'Full form design with questions (field types, labels, choices, validation), layout (field ordering), and conditions',
|
||||
},
|
||||
updated: { type: 'string', description: 'Last updated timestamp', optional: true },
|
||||
publish: {
|
||||
type: 'json',
|
||||
description: 'Publishing and request type configuration',
|
||||
optional: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
import type { JsmGetFormTemplatesParams, JsmGetFormTemplatesResponse } from '@/tools/jsm/types'
|
||||
import { FORM_TEMPLATE_PROPERTIES } from '@/tools/jsm/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const jsmGetFormTemplatesTool: ToolConfig<
|
||||
JsmGetFormTemplatesParams,
|
||||
JsmGetFormTemplatesResponse
|
||||
> = {
|
||||
id: 'jsm_get_form_templates',
|
||||
name: 'JSM Get Form Templates',
|
||||
description:
|
||||
'List forms (ProForma/JSM Forms) in a Jira project to discover form IDs for request types',
|
||||
version: '1.0.0',
|
||||
|
||||
oauth: {
|
||||
required: true,
|
||||
provider: 'jira',
|
||||
},
|
||||
|
||||
params: {
|
||||
accessToken: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'hidden',
|
||||
description: 'OAuth access token for Jira Service Management',
|
||||
},
|
||||
domain: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Your Jira domain (e.g., yourcompany.atlassian.net)',
|
||||
},
|
||||
cloudId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'hidden',
|
||||
description: 'Jira Cloud ID for the instance',
|
||||
},
|
||||
projectIdOrKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Jira project ID or key (e.g., "10001" or "SD")',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: '/api/tools/jsm/forms/templates',
|
||||
method: 'POST',
|
||||
headers: () => ({
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
body: (params) => ({
|
||||
domain: params.domain,
|
||||
accessToken: params.accessToken,
|
||||
cloudId: params.cloudId,
|
||||
projectIdOrKey: params.projectIdOrKey,
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const responseText = await response.text()
|
||||
|
||||
if (!responseText) {
|
||||
return {
|
||||
success: false,
|
||||
output: {
|
||||
ts: new Date().toISOString(),
|
||||
projectIdOrKey: '',
|
||||
templates: [],
|
||||
total: 0,
|
||||
},
|
||||
error: 'Empty response from API',
|
||||
}
|
||||
}
|
||||
|
||||
const data = JSON.parse(responseText)
|
||||
|
||||
if (data.success && data.output) {
|
||||
return data
|
||||
}
|
||||
|
||||
return {
|
||||
success: data.success || false,
|
||||
output: data.output || {
|
||||
ts: new Date().toISOString(),
|
||||
projectIdOrKey: '',
|
||||
templates: [],
|
||||
total: 0,
|
||||
},
|
||||
error: data.error,
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
ts: { type: 'string', description: 'Timestamp of the operation' },
|
||||
projectIdOrKey: { type: 'string', description: 'Project ID or key' },
|
||||
templates: {
|
||||
type: 'array',
|
||||
description: 'List of forms in the project',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: FORM_TEMPLATE_PROPERTIES,
|
||||
},
|
||||
},
|
||||
total: { type: 'number', description: 'Total number of forms' },
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
import type { JsmGetIssueFormsParams, JsmGetIssueFormsResponse } from '@/tools/jsm/types'
|
||||
import { ISSUE_FORM_PROPERTIES } from '@/tools/jsm/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const jsmGetIssueFormsTool: ToolConfig<JsmGetIssueFormsParams, JsmGetIssueFormsResponse> = {
|
||||
id: 'jsm_get_issue_forms',
|
||||
name: 'JSM Get Issue Forms',
|
||||
description:
|
||||
'List forms (ProForma/JSM Forms) attached to a Jira issue with metadata (name, submitted status, lock)',
|
||||
version: '1.0.0',
|
||||
|
||||
oauth: {
|
||||
required: true,
|
||||
provider: 'jira',
|
||||
},
|
||||
|
||||
params: {
|
||||
accessToken: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'hidden',
|
||||
description: 'OAuth access token for Jira Service Management',
|
||||
},
|
||||
domain: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Your Jira domain (e.g., yourcompany.atlassian.net)',
|
||||
},
|
||||
cloudId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'hidden',
|
||||
description: 'Jira Cloud ID for the instance',
|
||||
},
|
||||
issueIdOrKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Issue ID or key (e.g., "SD-123", "10001")',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: '/api/tools/jsm/forms/issue',
|
||||
method: 'POST',
|
||||
headers: () => ({
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
body: (params) => ({
|
||||
domain: params.domain,
|
||||
accessToken: params.accessToken,
|
||||
cloudId: params.cloudId,
|
||||
issueIdOrKey: params.issueIdOrKey,
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const responseText = await response.text()
|
||||
|
||||
if (!responseText) {
|
||||
return {
|
||||
success: false,
|
||||
output: {
|
||||
ts: new Date().toISOString(),
|
||||
issueIdOrKey: '',
|
||||
forms: [],
|
||||
total: 0,
|
||||
},
|
||||
error: 'Empty response from API',
|
||||
}
|
||||
}
|
||||
|
||||
const data = JSON.parse(responseText)
|
||||
|
||||
if (data.success && data.output) {
|
||||
return data
|
||||
}
|
||||
|
||||
return {
|
||||
success: data.success || false,
|
||||
output: data.output || {
|
||||
ts: new Date().toISOString(),
|
||||
issueIdOrKey: '',
|
||||
forms: [],
|
||||
total: 0,
|
||||
},
|
||||
error: data.error,
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
ts: { type: 'string', description: 'Timestamp of the operation' },
|
||||
issueIdOrKey: { type: 'string', description: 'Issue ID or key' },
|
||||
forms: {
|
||||
type: 'array',
|
||||
description: 'List of forms attached to the issue',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: ISSUE_FORM_PROPERTIES,
|
||||
},
|
||||
},
|
||||
total: { type: 'number', description: 'Total number of forms' },
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
import type { JsmGetObjectParams, JsmGetObjectResponse } from '@/tools/jsm/types'
|
||||
import { ASSET_OBJECT_PROPERTIES } from '@/tools/jsm/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const jsmGetObjectTool: ToolConfig<JsmGetObjectParams, JsmGetObjectResponse> = {
|
||||
id: 'jsm_get_object',
|
||||
name: 'JSM Get Asset Object',
|
||||
description: 'Get a single Assets (Insight/CMDB) object by ID, including its attribute values',
|
||||
version: '1.0.0',
|
||||
|
||||
oauth: {
|
||||
required: true,
|
||||
provider: 'jira',
|
||||
},
|
||||
|
||||
params: {
|
||||
accessToken: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'hidden',
|
||||
description: 'OAuth access token for Jira Service Management',
|
||||
},
|
||||
domain: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Your Jira domain (e.g., yourcompany.atlassian.net)',
|
||||
},
|
||||
cloudId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'hidden',
|
||||
description: 'Jira Cloud ID for the instance',
|
||||
},
|
||||
workspaceId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'hidden',
|
||||
description: 'Assets workspace ID (resolved automatically when omitted)',
|
||||
},
|
||||
objectId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'The Assets object ID',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: '/api/tools/jsm/assets/object/get',
|
||||
method: 'POST',
|
||||
headers: () => ({ 'Content-Type': 'application/json' }),
|
||||
body: (params) => ({
|
||||
domain: params.domain,
|
||||
accessToken: params.accessToken,
|
||||
cloudId: params.cloudId,
|
||||
workspaceId: params.workspaceId,
|
||||
objectId: params.objectId?.trim(),
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const responseText = await response.text()
|
||||
if (!responseText) {
|
||||
return {
|
||||
success: false,
|
||||
output: { ts: new Date().toISOString(), object: null },
|
||||
error: 'Empty response from API',
|
||||
}
|
||||
}
|
||||
const data = JSON.parse(responseText)
|
||||
if (data.success && data.output) return data
|
||||
return {
|
||||
success: data.success || false,
|
||||
output: data.output || { ts: new Date().toISOString(), object: null },
|
||||
error: data.error,
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
ts: { type: 'string', description: 'Timestamp of the operation' },
|
||||
object: {
|
||||
type: 'json',
|
||||
description: 'The Assets object',
|
||||
properties: ASSET_OBJECT_PROPERTIES,
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
import type { JsmGetObjectSchemaParams, JsmGetObjectSchemaResponse } from '@/tools/jsm/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const jsmGetObjectSchemaTool: ToolConfig<
|
||||
JsmGetObjectSchemaParams,
|
||||
JsmGetObjectSchemaResponse
|
||||
> = {
|
||||
id: 'jsm_get_object_schema',
|
||||
name: 'JSM Get Asset Schema',
|
||||
description: 'Get a single Assets (Insight/CMDB) object schema by ID',
|
||||
version: '1.0.0',
|
||||
|
||||
oauth: {
|
||||
required: true,
|
||||
provider: 'jira',
|
||||
},
|
||||
|
||||
params: {
|
||||
accessToken: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'hidden',
|
||||
description: 'OAuth access token for Jira Service Management',
|
||||
},
|
||||
domain: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Your Jira domain (e.g., yourcompany.atlassian.net)',
|
||||
},
|
||||
cloudId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'hidden',
|
||||
description: 'Jira Cloud ID for the instance',
|
||||
},
|
||||
workspaceId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'hidden',
|
||||
description: 'Assets workspace ID (resolved automatically when omitted)',
|
||||
},
|
||||
schemaId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'The Assets object schema ID',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: '/api/tools/jsm/assets/schema',
|
||||
method: 'POST',
|
||||
headers: () => ({ 'Content-Type': 'application/json' }),
|
||||
body: (params) => ({
|
||||
domain: params.domain,
|
||||
accessToken: params.accessToken,
|
||||
cloudId: params.cloudId,
|
||||
workspaceId: params.workspaceId,
|
||||
schemaId: params.schemaId?.trim(),
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const responseText = await response.text()
|
||||
if (!responseText) {
|
||||
return {
|
||||
success: false,
|
||||
output: { ts: new Date().toISOString(), schema: null },
|
||||
error: 'Empty response from API',
|
||||
}
|
||||
}
|
||||
const data = JSON.parse(responseText)
|
||||
if (data.success && data.output) return data
|
||||
return {
|
||||
success: data.success || false,
|
||||
output: data.output || { ts: new Date().toISOString(), schema: null },
|
||||
error: data.error,
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
ts: { type: 'string', description: 'Timestamp of the operation' },
|
||||
schema: {
|
||||
type: 'json',
|
||||
description: 'The Assets object schema',
|
||||
properties: {
|
||||
id: { type: 'string', description: 'Schema ID' },
|
||||
name: { type: 'string', description: 'Schema name' },
|
||||
objectSchemaKey: { type: 'string', description: 'Schema key' },
|
||||
status: { type: 'string', description: 'Schema status' },
|
||||
description: { type: 'string', description: 'Schema description', optional: true },
|
||||
objectCount: { type: 'number', description: 'Number of objects', optional: true },
|
||||
objectTypeCount: {
|
||||
type: 'number',
|
||||
description: 'Number of object types',
|
||||
optional: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
import type {
|
||||
JsmGetObjectTypeAttributesParams,
|
||||
JsmGetObjectTypeAttributesResponse,
|
||||
} from '@/tools/jsm/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const jsmGetObjectTypeAttributesTool: ToolConfig<
|
||||
JsmGetObjectTypeAttributesParams,
|
||||
JsmGetObjectTypeAttributesResponse
|
||||
> = {
|
||||
id: 'jsm_get_object_type_attributes',
|
||||
name: 'JSM Get Asset Object Type Attributes',
|
||||
description:
|
||||
'Get the attribute definitions for an Assets (Insight/CMDB) object type. Use the returned attribute IDs to build create/update payloads or map columns.',
|
||||
version: '1.0.0',
|
||||
|
||||
oauth: {
|
||||
required: true,
|
||||
provider: 'jira',
|
||||
},
|
||||
|
||||
params: {
|
||||
accessToken: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'hidden',
|
||||
description: 'OAuth access token for Jira Service Management',
|
||||
},
|
||||
domain: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Your Jira domain (e.g., yourcompany.atlassian.net)',
|
||||
},
|
||||
cloudId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'hidden',
|
||||
description: 'Jira Cloud ID for the instance',
|
||||
},
|
||||
workspaceId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'hidden',
|
||||
description: 'Assets workspace ID (resolved automatically when omitted)',
|
||||
},
|
||||
objectTypeId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'The Assets object type ID',
|
||||
},
|
||||
onlyValueEditable: {
|
||||
type: 'boolean',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Return only attributes whose values can be edited',
|
||||
},
|
||||
query: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Filter attributes by a search query',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: '/api/tools/jsm/assets/attributes',
|
||||
method: 'POST',
|
||||
headers: () => ({ 'Content-Type': 'application/json' }),
|
||||
body: (params) => ({
|
||||
domain: params.domain,
|
||||
accessToken: params.accessToken,
|
||||
cloudId: params.cloudId,
|
||||
workspaceId: params.workspaceId,
|
||||
objectTypeId: params.objectTypeId?.trim(),
|
||||
onlyValueEditable: params.onlyValueEditable,
|
||||
query: params.query,
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const responseText = await response.text()
|
||||
if (!responseText) {
|
||||
return {
|
||||
success: false,
|
||||
output: { ts: new Date().toISOString(), attributes: [], total: 0 },
|
||||
error: 'Empty response from API',
|
||||
}
|
||||
}
|
||||
const data = JSON.parse(responseText)
|
||||
if (data.success && data.output) return data
|
||||
return {
|
||||
success: data.success || false,
|
||||
output: data.output || { ts: new Date().toISOString(), attributes: [], total: 0 },
|
||||
error: data.error,
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
ts: { type: 'string', description: 'Timestamp of the operation' },
|
||||
attributes: {
|
||||
type: 'array',
|
||||
description: 'Attribute definitions for the object type',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: {
|
||||
type: 'string',
|
||||
description: 'Attribute definition ID — use as objectTypeAttributeId in create/update',
|
||||
},
|
||||
name: { type: 'string', description: 'Attribute name' },
|
||||
label: { type: 'boolean', description: 'Whether this attribute is the object label' },
|
||||
type: { type: 'number', description: 'Data type discriminator (integer enum)' },
|
||||
defaultType: {
|
||||
type: 'json',
|
||||
description: 'Default data type { id, name }',
|
||||
optional: true,
|
||||
},
|
||||
editable: { type: 'boolean', description: 'Whether the value is editable' },
|
||||
minimumCardinality: {
|
||||
type: 'number',
|
||||
description: 'Minimum number of values (>= 1 means required)',
|
||||
},
|
||||
maximumCardinality: { type: 'number', description: 'Maximum number of values' },
|
||||
uniqueAttribute: {
|
||||
type: 'boolean',
|
||||
description: 'Whether values must be unique',
|
||||
optional: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
total: { type: 'number', description: 'Total number of attributes' },
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
import type { JsmGetOrganizationsParams, JsmGetOrganizationsResponse } from '@/tools/jsm/types'
|
||||
import { ORGANIZATION_ITEM_PROPERTIES } from '@/tools/jsm/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const jsmGetOrganizationsTool: ToolConfig<
|
||||
JsmGetOrganizationsParams,
|
||||
JsmGetOrganizationsResponse
|
||||
> = {
|
||||
id: 'jsm_get_organizations',
|
||||
name: 'JSM Get Organizations',
|
||||
description: 'Get organizations for a service desk in Jira Service Management',
|
||||
version: '1.0.0',
|
||||
|
||||
oauth: {
|
||||
required: true,
|
||||
provider: 'jira',
|
||||
},
|
||||
|
||||
params: {
|
||||
accessToken: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'hidden',
|
||||
description: 'OAuth access token for Jira Service Management',
|
||||
},
|
||||
domain: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Your Jira domain (e.g., yourcompany.atlassian.net)',
|
||||
},
|
||||
cloudId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'hidden',
|
||||
description: 'Jira Cloud ID for the instance',
|
||||
},
|
||||
serviceDeskId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Service Desk ID (e.g., "1", "2")',
|
||||
},
|
||||
start: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Start index for pagination (e.g., 0, 50, 100)',
|
||||
},
|
||||
limit: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Maximum results to return (e.g., 10, 25, 50)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: '/api/tools/jsm/organizations',
|
||||
method: 'POST',
|
||||
headers: () => ({
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
body: (params) => ({
|
||||
domain: params.domain,
|
||||
accessToken: params.accessToken,
|
||||
cloudId: params.cloudId,
|
||||
serviceDeskId: params.serviceDeskId,
|
||||
start: params.start,
|
||||
limit: params.limit,
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const responseText = await response.text()
|
||||
|
||||
if (!responseText) {
|
||||
return {
|
||||
success: false,
|
||||
output: {
|
||||
ts: new Date().toISOString(),
|
||||
organizations: [],
|
||||
total: 0,
|
||||
isLastPage: true,
|
||||
},
|
||||
error: 'Empty response from API',
|
||||
}
|
||||
}
|
||||
|
||||
const data = JSON.parse(responseText)
|
||||
|
||||
if (data.success && data.output) {
|
||||
return data
|
||||
}
|
||||
|
||||
return {
|
||||
success: data.success || false,
|
||||
output: data.output || {
|
||||
ts: new Date().toISOString(),
|
||||
organizations: [],
|
||||
total: 0,
|
||||
isLastPage: true,
|
||||
},
|
||||
error: data.error,
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
ts: { type: 'string', description: 'Timestamp of the operation' },
|
||||
organizations: {
|
||||
type: 'array',
|
||||
description: 'List of organizations',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: ORGANIZATION_ITEM_PROPERTIES,
|
||||
},
|
||||
},
|
||||
total: { type: 'number', description: 'Total number of organizations' },
|
||||
isLastPage: { type: 'boolean', description: 'Whether this is the last page' },
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
import type { JsmGetParticipantsParams, JsmGetParticipantsResponse } from '@/tools/jsm/types'
|
||||
import { PARTICIPANT_ITEM_PROPERTIES } from '@/tools/jsm/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const jsmGetParticipantsTool: ToolConfig<
|
||||
JsmGetParticipantsParams,
|
||||
JsmGetParticipantsResponse
|
||||
> = {
|
||||
id: 'jsm_get_participants',
|
||||
name: 'JSM Get Participants',
|
||||
description: 'Get participants for a request in Jira Service Management',
|
||||
version: '1.0.0',
|
||||
|
||||
oauth: {
|
||||
required: true,
|
||||
provider: 'jira',
|
||||
},
|
||||
|
||||
params: {
|
||||
accessToken: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'hidden',
|
||||
description: 'OAuth access token for Jira Service Management',
|
||||
},
|
||||
domain: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Your Jira domain (e.g., yourcompany.atlassian.net)',
|
||||
},
|
||||
cloudId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'hidden',
|
||||
description: 'Jira Cloud ID for the instance',
|
||||
},
|
||||
issueIdOrKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Issue ID or key (e.g., SD-123)',
|
||||
},
|
||||
start: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Start index for pagination (e.g., 0, 50, 100)',
|
||||
},
|
||||
limit: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Maximum results to return (e.g., 10, 25, 50)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: '/api/tools/jsm/participants',
|
||||
method: 'POST',
|
||||
headers: () => ({
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
body: (params) => ({
|
||||
domain: params.domain,
|
||||
accessToken: params.accessToken,
|
||||
cloudId: params.cloudId,
|
||||
issueIdOrKey: params.issueIdOrKey,
|
||||
start: params.start,
|
||||
limit: params.limit,
|
||||
action: 'get',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const responseText = await response.text()
|
||||
|
||||
if (!responseText) {
|
||||
return {
|
||||
success: false,
|
||||
output: {
|
||||
ts: new Date().toISOString(),
|
||||
issueIdOrKey: '',
|
||||
participants: [],
|
||||
total: 0,
|
||||
isLastPage: true,
|
||||
},
|
||||
error: 'Empty response from API',
|
||||
}
|
||||
}
|
||||
|
||||
const data = JSON.parse(responseText)
|
||||
|
||||
if (data.success && data.output) {
|
||||
return data
|
||||
}
|
||||
|
||||
return {
|
||||
success: data.success || false,
|
||||
output: data.output || {
|
||||
ts: new Date().toISOString(),
|
||||
issueIdOrKey: '',
|
||||
participants: [],
|
||||
total: 0,
|
||||
isLastPage: true,
|
||||
},
|
||||
error: data.error,
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
ts: { type: 'string', description: 'Timestamp of the operation' },
|
||||
issueIdOrKey: { type: 'string', description: 'Issue ID or key' },
|
||||
participants: {
|
||||
type: 'array',
|
||||
description: 'List of participants',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: PARTICIPANT_ITEM_PROPERTIES,
|
||||
},
|
||||
},
|
||||
total: { type: 'number', description: 'Total number of participants' },
|
||||
isLastPage: { type: 'boolean', description: 'Whether this is the last page' },
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
import type { JsmGetQueuesParams, JsmGetQueuesResponse } from '@/tools/jsm/types'
|
||||
import { QUEUE_ITEM_PROPERTIES } from '@/tools/jsm/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const jsmGetQueuesTool: ToolConfig<JsmGetQueuesParams, JsmGetQueuesResponse> = {
|
||||
id: 'jsm_get_queues',
|
||||
name: 'JSM Get Queues',
|
||||
description: 'Get queues for a service desk in Jira Service Management',
|
||||
version: '1.0.0',
|
||||
|
||||
oauth: {
|
||||
required: true,
|
||||
provider: 'jira',
|
||||
},
|
||||
|
||||
params: {
|
||||
accessToken: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'hidden',
|
||||
description: 'OAuth access token for Jira Service Management',
|
||||
},
|
||||
domain: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Your Jira domain (e.g., yourcompany.atlassian.net)',
|
||||
},
|
||||
cloudId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'hidden',
|
||||
description: 'Jira Cloud ID for the instance',
|
||||
},
|
||||
serviceDeskId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Service Desk ID (e.g., "1", "2")',
|
||||
},
|
||||
includeCount: {
|
||||
type: 'boolean',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Include issue count for each queue (true/false)',
|
||||
},
|
||||
start: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Start index for pagination (e.g., 0, 50, 100)',
|
||||
},
|
||||
limit: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Maximum results to return (e.g., 10, 25, 50)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: '/api/tools/jsm/queues',
|
||||
method: 'POST',
|
||||
headers: () => ({
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
body: (params) => ({
|
||||
domain: params.domain,
|
||||
accessToken: params.accessToken,
|
||||
cloudId: params.cloudId,
|
||||
serviceDeskId: params.serviceDeskId,
|
||||
includeCount: params.includeCount,
|
||||
start: params.start,
|
||||
limit: params.limit,
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const responseText = await response.text()
|
||||
|
||||
if (!responseText) {
|
||||
return {
|
||||
success: false,
|
||||
output: {
|
||||
ts: new Date().toISOString(),
|
||||
queues: [],
|
||||
total: 0,
|
||||
isLastPage: true,
|
||||
},
|
||||
error: 'Empty response from API',
|
||||
}
|
||||
}
|
||||
|
||||
const data = JSON.parse(responseText)
|
||||
|
||||
if (data.success && data.output) {
|
||||
return data
|
||||
}
|
||||
|
||||
return {
|
||||
success: data.success || false,
|
||||
output: data.output || {
|
||||
ts: new Date().toISOString(),
|
||||
queues: [],
|
||||
total: 0,
|
||||
isLastPage: true,
|
||||
},
|
||||
error: data.error,
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
ts: { type: 'string', description: 'Timestamp of the operation' },
|
||||
queues: {
|
||||
type: 'array',
|
||||
description: 'List of queues',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: QUEUE_ITEM_PROPERTIES,
|
||||
},
|
||||
},
|
||||
total: { type: 'number', description: 'Total number of queues' },
|
||||
isLastPage: { type: 'boolean', description: 'Whether this is the last page' },
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,152 @@
|
||||
import type { JsmGetRequestParams, JsmGetRequestResponse } from '@/tools/jsm/types'
|
||||
import {
|
||||
REQUEST_FIELD_VALUE_PROPERTIES,
|
||||
REQUEST_STATUS_PROPERTIES,
|
||||
USER_OUTPUT_PROPERTIES,
|
||||
} from '@/tools/jsm/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const jsmGetRequestTool: ToolConfig<JsmGetRequestParams, JsmGetRequestResponse> = {
|
||||
id: 'jsm_get_request',
|
||||
name: 'JSM Get Request',
|
||||
description: 'Get a single service request from Jira Service Management',
|
||||
version: '1.0.0',
|
||||
|
||||
oauth: {
|
||||
required: true,
|
||||
provider: 'jira',
|
||||
},
|
||||
|
||||
params: {
|
||||
accessToken: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'hidden',
|
||||
description: 'OAuth access token for Jira Service Management',
|
||||
},
|
||||
domain: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Your Jira domain (e.g., yourcompany.atlassian.net)',
|
||||
},
|
||||
cloudId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'hidden',
|
||||
description: 'Jira Cloud ID for the instance',
|
||||
},
|
||||
issueIdOrKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Issue ID or key (e.g., SD-123)',
|
||||
},
|
||||
expand: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description:
|
||||
'Comma-separated fields to expand: participant, status, sla, requestType, serviceDesk, attachment, comment, action',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: '/api/tools/jsm/request',
|
||||
method: 'POST',
|
||||
headers: () => ({
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
body: (params) => ({
|
||||
domain: params.domain,
|
||||
accessToken: params.accessToken,
|
||||
cloudId: params.cloudId,
|
||||
issueIdOrKey: params.issueIdOrKey,
|
||||
expand: params.expand,
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const responseText = await response.text()
|
||||
|
||||
if (!responseText) {
|
||||
return {
|
||||
success: false,
|
||||
output: {
|
||||
ts: new Date().toISOString(),
|
||||
issueId: '',
|
||||
issueKey: '',
|
||||
requestTypeId: '',
|
||||
serviceDeskId: '',
|
||||
createdDate: null,
|
||||
currentStatus: null,
|
||||
reporter: null,
|
||||
requestFieldValues: [],
|
||||
url: '',
|
||||
},
|
||||
error: 'Empty response from API',
|
||||
}
|
||||
}
|
||||
|
||||
const data = JSON.parse(responseText)
|
||||
|
||||
if (data.success && data.output) {
|
||||
return data
|
||||
}
|
||||
|
||||
return {
|
||||
success: data.success || false,
|
||||
output: data.output || {
|
||||
ts: new Date().toISOString(),
|
||||
issueId: '',
|
||||
issueKey: '',
|
||||
requestTypeId: '',
|
||||
serviceDeskId: '',
|
||||
createdDate: null,
|
||||
currentStatus: null,
|
||||
reporter: null,
|
||||
requestFieldValues: [],
|
||||
url: '',
|
||||
},
|
||||
error: data.error,
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
ts: { type: 'string', description: 'Timestamp of the operation' },
|
||||
issueId: { type: 'string', description: 'Jira issue ID' },
|
||||
issueKey: { type: 'string', description: 'Issue key (e.g., SD-123)' },
|
||||
requestTypeId: { type: 'string', description: 'Request type ID' },
|
||||
serviceDeskId: { type: 'string', description: 'Service desk ID' },
|
||||
createdDate: {
|
||||
type: 'json',
|
||||
description: 'Creation date with iso8601, friendly, epochMillis',
|
||||
optional: true,
|
||||
},
|
||||
currentStatus: {
|
||||
type: 'object',
|
||||
description: 'Current request status',
|
||||
properties: REQUEST_STATUS_PROPERTIES,
|
||||
optional: true,
|
||||
},
|
||||
reporter: {
|
||||
type: 'object',
|
||||
description: 'Reporter user details',
|
||||
properties: USER_OUTPUT_PROPERTIES,
|
||||
optional: true,
|
||||
},
|
||||
requestFieldValues: {
|
||||
type: 'array',
|
||||
description: 'Request field values',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: REQUEST_FIELD_VALUE_PROPERTIES,
|
||||
},
|
||||
},
|
||||
url: { type: 'string', description: 'URL to the request' },
|
||||
request: {
|
||||
type: 'json',
|
||||
description: 'The service request object',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
import type {
|
||||
JsmGetRequestTypeFieldsParams,
|
||||
JsmGetRequestTypeFieldsResponse,
|
||||
} from '@/tools/jsm/types'
|
||||
import { REQUEST_TYPE_FIELD_PROPERTIES } from '@/tools/jsm/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const jsmGetRequestTypeFieldsTool: ToolConfig<
|
||||
JsmGetRequestTypeFieldsParams,
|
||||
JsmGetRequestTypeFieldsResponse
|
||||
> = {
|
||||
id: 'jsm_get_request_type_fields',
|
||||
name: 'JSM Get Request Type Fields',
|
||||
description:
|
||||
'Get the fields required to create a request of a specific type in Jira Service Management',
|
||||
version: '1.0.0',
|
||||
|
||||
oauth: {
|
||||
required: true,
|
||||
provider: 'jira',
|
||||
},
|
||||
|
||||
params: {
|
||||
accessToken: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'hidden',
|
||||
description: 'OAuth access token for Jira Service Management',
|
||||
},
|
||||
domain: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Your Jira domain (e.g., yourcompany.atlassian.net)',
|
||||
},
|
||||
cloudId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'hidden',
|
||||
description: 'Jira Cloud ID for the instance',
|
||||
},
|
||||
serviceDeskId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Service Desk ID (e.g., "1", "2")',
|
||||
},
|
||||
requestTypeId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Request Type ID (e.g., "10", "15")',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: '/api/tools/jsm/requesttypefields',
|
||||
method: 'POST',
|
||||
headers: () => ({
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
body: (params) => ({
|
||||
domain: params.domain,
|
||||
accessToken: params.accessToken,
|
||||
cloudId: params.cloudId,
|
||||
serviceDeskId: params.serviceDeskId,
|
||||
requestTypeId: params.requestTypeId,
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const responseText = await response.text()
|
||||
|
||||
if (!responseText) {
|
||||
return {
|
||||
success: false,
|
||||
output: {
|
||||
ts: new Date().toISOString(),
|
||||
serviceDeskId: '',
|
||||
requestTypeId: '',
|
||||
canAddRequestParticipants: false,
|
||||
canRaiseOnBehalfOf: false,
|
||||
requestTypeFields: [],
|
||||
},
|
||||
error: 'Empty response from API',
|
||||
}
|
||||
}
|
||||
|
||||
const data = JSON.parse(responseText)
|
||||
|
||||
if (data.success && data.output) {
|
||||
return data
|
||||
}
|
||||
|
||||
return {
|
||||
success: data.success || false,
|
||||
output: data.output || {
|
||||
ts: new Date().toISOString(),
|
||||
serviceDeskId: '',
|
||||
requestTypeId: '',
|
||||
canAddRequestParticipants: false,
|
||||
canRaiseOnBehalfOf: false,
|
||||
requestTypeFields: [],
|
||||
},
|
||||
error: data.error,
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
ts: { type: 'string', description: 'Timestamp of the operation' },
|
||||
serviceDeskId: { type: 'string', description: 'Service desk ID' },
|
||||
requestTypeId: { type: 'string', description: 'Request type ID' },
|
||||
canAddRequestParticipants: {
|
||||
type: 'boolean',
|
||||
description: 'Whether participants can be added to requests of this type',
|
||||
},
|
||||
canRaiseOnBehalfOf: {
|
||||
type: 'boolean',
|
||||
description: 'Whether requests can be raised on behalf of another user',
|
||||
},
|
||||
requestTypeFields: {
|
||||
type: 'array',
|
||||
description: 'List of fields for this request type',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: REQUEST_TYPE_FIELD_PROPERTIES,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
import type { JsmGetRequestTypesParams, JsmGetRequestTypesResponse } from '@/tools/jsm/types'
|
||||
import { REQUEST_TYPE_ITEM_PROPERTIES } from '@/tools/jsm/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const jsmGetRequestTypesTool: ToolConfig<
|
||||
JsmGetRequestTypesParams,
|
||||
JsmGetRequestTypesResponse
|
||||
> = {
|
||||
id: 'jsm_get_request_types',
|
||||
name: 'JSM Get Request Types',
|
||||
description: 'Get request types for a service desk in Jira Service Management',
|
||||
version: '1.0.0',
|
||||
|
||||
oauth: {
|
||||
required: true,
|
||||
provider: 'jira',
|
||||
},
|
||||
|
||||
params: {
|
||||
accessToken: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'hidden',
|
||||
description: 'OAuth access token for Jira Service Management',
|
||||
},
|
||||
domain: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Your Jira domain (e.g., yourcompany.atlassian.net)',
|
||||
},
|
||||
cloudId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'hidden',
|
||||
description: 'Jira Cloud ID for the instance',
|
||||
},
|
||||
serviceDeskId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Service Desk ID (e.g., "1", "2")',
|
||||
},
|
||||
searchQuery: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Filter request types by name',
|
||||
},
|
||||
groupId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Filter by request type group ID',
|
||||
},
|
||||
expand: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Comma-separated fields to expand in the response',
|
||||
},
|
||||
start: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Start index for pagination (e.g., 0, 50, 100)',
|
||||
},
|
||||
limit: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Maximum results to return (e.g., 10, 25, 50)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: '/api/tools/jsm/requesttypes',
|
||||
method: 'POST',
|
||||
headers: () => ({
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
body: (params) => ({
|
||||
domain: params.domain,
|
||||
accessToken: params.accessToken,
|
||||
cloudId: params.cloudId,
|
||||
serviceDeskId: params.serviceDeskId,
|
||||
searchQuery: params.searchQuery,
|
||||
groupId: params.groupId,
|
||||
expand: params.expand,
|
||||
start: params.start,
|
||||
limit: params.limit,
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const responseText = await response.text()
|
||||
|
||||
if (!responseText) {
|
||||
return {
|
||||
success: false,
|
||||
output: {
|
||||
ts: new Date().toISOString(),
|
||||
requestTypes: [],
|
||||
total: 0,
|
||||
isLastPage: true,
|
||||
},
|
||||
error: 'Empty response from API',
|
||||
}
|
||||
}
|
||||
|
||||
const data = JSON.parse(responseText)
|
||||
|
||||
if (data.success && data.output) {
|
||||
return data
|
||||
}
|
||||
|
||||
return {
|
||||
success: data.success || false,
|
||||
output: data.output || {
|
||||
ts: new Date().toISOString(),
|
||||
requestTypes: [],
|
||||
total: 0,
|
||||
isLastPage: true,
|
||||
},
|
||||
error: data.error,
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
ts: { type: 'string', description: 'Timestamp of the operation' },
|
||||
requestTypes: {
|
||||
type: 'array',
|
||||
description: 'List of request types',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: REQUEST_TYPE_ITEM_PROPERTIES,
|
||||
},
|
||||
},
|
||||
total: { type: 'number', description: 'Total number of request types' },
|
||||
isLastPage: { type: 'boolean', description: 'Whether this is the last page' },
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
import type { JsmGetRequestsParams, JsmGetRequestsResponse } from '@/tools/jsm/types'
|
||||
import { REQUEST_ITEM_PROPERTIES } from '@/tools/jsm/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const jsmGetRequestsTool: ToolConfig<JsmGetRequestsParams, JsmGetRequestsResponse> = {
|
||||
id: 'jsm_get_requests',
|
||||
name: 'JSM Get Requests',
|
||||
description: 'Get multiple service requests from Jira Service Management',
|
||||
version: '1.0.0',
|
||||
|
||||
oauth: {
|
||||
required: true,
|
||||
provider: 'jira',
|
||||
},
|
||||
|
||||
params: {
|
||||
accessToken: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'hidden',
|
||||
description: 'OAuth access token for Jira Service Management',
|
||||
},
|
||||
domain: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Your Jira domain (e.g., yourcompany.atlassian.net)',
|
||||
},
|
||||
cloudId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'hidden',
|
||||
description: 'Jira Cloud ID for the instance',
|
||||
},
|
||||
serviceDeskId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Filter by service desk ID (e.g., "1", "2")',
|
||||
},
|
||||
requestOwnership: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description:
|
||||
'Filter by ownership: OWNED_REQUESTS, PARTICIPATED_REQUESTS, APPROVER, ALL_REQUESTS',
|
||||
},
|
||||
requestStatus: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Filter by status: OPEN_REQUESTS, CLOSED_REQUESTS, ALL_REQUESTS',
|
||||
},
|
||||
requestTypeId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Filter by request type ID',
|
||||
},
|
||||
searchTerm: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Search term to filter requests (e.g., "password reset", "laptop")',
|
||||
},
|
||||
expand: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description:
|
||||
'Comma-separated fields to expand: participant, status, sla, requestType, serviceDesk, attachment, comment, action',
|
||||
},
|
||||
start: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Start index for pagination (e.g., 0, 50, 100)',
|
||||
},
|
||||
limit: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Maximum results to return (e.g., 10, 25, 50)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: '/api/tools/jsm/requests',
|
||||
method: 'POST',
|
||||
headers: () => ({
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
body: (params) => ({
|
||||
domain: params.domain,
|
||||
accessToken: params.accessToken,
|
||||
cloudId: params.cloudId,
|
||||
serviceDeskId: params.serviceDeskId,
|
||||
requestOwnership: params.requestOwnership,
|
||||
requestStatus: params.requestStatus,
|
||||
requestTypeId: params.requestTypeId,
|
||||
searchTerm: params.searchTerm,
|
||||
expand: params.expand,
|
||||
start: params.start,
|
||||
limit: params.limit,
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const responseText = await response.text()
|
||||
|
||||
if (!responseText) {
|
||||
return {
|
||||
success: false,
|
||||
output: {
|
||||
ts: new Date().toISOString(),
|
||||
requests: [],
|
||||
total: 0,
|
||||
isLastPage: true,
|
||||
},
|
||||
error: 'Empty response from API',
|
||||
}
|
||||
}
|
||||
|
||||
const data = JSON.parse(responseText)
|
||||
|
||||
if (data.success && data.output) {
|
||||
return data
|
||||
}
|
||||
|
||||
return {
|
||||
success: data.success || false,
|
||||
output: data.output || {
|
||||
ts: new Date().toISOString(),
|
||||
requests: [],
|
||||
total: 0,
|
||||
isLastPage: true,
|
||||
},
|
||||
error: data.error,
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
ts: { type: 'string', description: 'Timestamp of the operation' },
|
||||
requests: {
|
||||
type: 'array',
|
||||
description: 'List of service requests',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: REQUEST_ITEM_PROPERTIES,
|
||||
},
|
||||
},
|
||||
total: { type: 'number', description: 'Total number of requests in current page' },
|
||||
isLastPage: { type: 'boolean', description: 'Whether this is the last page' },
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
import type { JsmGetServiceDesksParams, JsmGetServiceDesksResponse } from '@/tools/jsm/types'
|
||||
import { SERVICE_DESK_ITEM_PROPERTIES } from '@/tools/jsm/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const jsmGetServiceDesksTool: ToolConfig<
|
||||
JsmGetServiceDesksParams,
|
||||
JsmGetServiceDesksResponse
|
||||
> = {
|
||||
id: 'jsm_get_service_desks',
|
||||
name: 'JSM Get Service Desks',
|
||||
description: 'Get all service desks from Jira Service Management',
|
||||
version: '1.0.0',
|
||||
|
||||
oauth: {
|
||||
required: true,
|
||||
provider: 'jira',
|
||||
},
|
||||
|
||||
params: {
|
||||
accessToken: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'hidden',
|
||||
description: 'OAuth access token for Jira Service Management',
|
||||
},
|
||||
domain: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Your Jira domain (e.g., yourcompany.atlassian.net)',
|
||||
},
|
||||
cloudId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'hidden',
|
||||
description: 'Jira Cloud ID for the instance',
|
||||
},
|
||||
expand: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Comma-separated fields to expand in the response',
|
||||
},
|
||||
start: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Start index for pagination (e.g., 0, 50, 100)',
|
||||
},
|
||||
limit: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Maximum results to return (e.g., 10, 25, 50)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: '/api/tools/jsm/servicedesks',
|
||||
method: 'POST',
|
||||
headers: () => ({
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
body: (params) => ({
|
||||
domain: params.domain,
|
||||
accessToken: params.accessToken,
|
||||
cloudId: params.cloudId,
|
||||
expand: params.expand,
|
||||
start: params.start,
|
||||
limit: params.limit,
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const responseText = await response.text()
|
||||
|
||||
if (!responseText) {
|
||||
return {
|
||||
success: false,
|
||||
output: {
|
||||
ts: new Date().toISOString(),
|
||||
serviceDesks: [],
|
||||
total: 0,
|
||||
isLastPage: true,
|
||||
},
|
||||
error: 'Empty response from API',
|
||||
}
|
||||
}
|
||||
|
||||
const data = JSON.parse(responseText)
|
||||
|
||||
if (data.success && data.output) {
|
||||
return data
|
||||
}
|
||||
|
||||
return {
|
||||
success: data.success || false,
|
||||
output: data.output || {
|
||||
ts: new Date().toISOString(),
|
||||
serviceDesks: [],
|
||||
total: 0,
|
||||
isLastPage: true,
|
||||
},
|
||||
error: data.error,
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
ts: { type: 'string', description: 'Timestamp of the operation' },
|
||||
serviceDesks: {
|
||||
type: 'array',
|
||||
description: 'List of service desks',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: SERVICE_DESK_ITEM_PROPERTIES,
|
||||
},
|
||||
},
|
||||
total: { type: 'number', description: 'Total number of service desks' },
|
||||
isLastPage: { type: 'boolean', description: 'Whether this is the last page' },
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
import type { JsmGetSlaParams, JsmGetSlaResponse } from '@/tools/jsm/types'
|
||||
import { SLA_ITEM_PROPERTIES } from '@/tools/jsm/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const jsmGetSlaTool: ToolConfig<JsmGetSlaParams, JsmGetSlaResponse> = {
|
||||
id: 'jsm_get_sla',
|
||||
name: 'JSM Get SLA',
|
||||
description: 'Get SLA information for a service request in Jira Service Management',
|
||||
version: '1.0.0',
|
||||
|
||||
oauth: {
|
||||
required: true,
|
||||
provider: 'jira',
|
||||
},
|
||||
|
||||
params: {
|
||||
accessToken: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'hidden',
|
||||
description: 'OAuth access token for Jira Service Management',
|
||||
},
|
||||
domain: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Your Jira domain (e.g., yourcompany.atlassian.net)',
|
||||
},
|
||||
cloudId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'hidden',
|
||||
description: 'Jira Cloud ID for the instance',
|
||||
},
|
||||
issueIdOrKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Issue ID or key (e.g., SD-123)',
|
||||
},
|
||||
start: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Start index for pagination (e.g., 0, 50, 100)',
|
||||
},
|
||||
limit: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Maximum results to return (e.g., 10, 25, 50)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: '/api/tools/jsm/sla',
|
||||
method: 'POST',
|
||||
headers: () => ({
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
body: (params) => ({
|
||||
domain: params.domain,
|
||||
accessToken: params.accessToken,
|
||||
cloudId: params.cloudId,
|
||||
issueIdOrKey: params.issueIdOrKey,
|
||||
start: params.start,
|
||||
limit: params.limit,
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const responseText = await response.text()
|
||||
|
||||
if (!responseText) {
|
||||
return {
|
||||
success: false,
|
||||
output: {
|
||||
ts: new Date().toISOString(),
|
||||
issueIdOrKey: '',
|
||||
slas: [],
|
||||
total: 0,
|
||||
isLastPage: true,
|
||||
},
|
||||
error: 'Empty response from API',
|
||||
}
|
||||
}
|
||||
|
||||
const data = JSON.parse(responseText)
|
||||
|
||||
if (data.success && data.output) {
|
||||
return data
|
||||
}
|
||||
|
||||
return {
|
||||
success: data.success || false,
|
||||
output: data.output || {
|
||||
ts: new Date().toISOString(),
|
||||
issueIdOrKey: '',
|
||||
slas: [],
|
||||
total: 0,
|
||||
isLastPage: true,
|
||||
},
|
||||
error: data.error,
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
ts: { type: 'string', description: 'Timestamp of the operation' },
|
||||
issueIdOrKey: { type: 'string', description: 'Issue ID or key' },
|
||||
slas: {
|
||||
type: 'array',
|
||||
description: 'List of SLA metrics',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: SLA_ITEM_PROPERTIES,
|
||||
},
|
||||
},
|
||||
total: { type: 'number', description: 'Total number of SLAs' },
|
||||
isLastPage: { type: 'boolean', description: 'Whether this is the last page' },
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
import type { JsmGetTransitionsParams, JsmGetTransitionsResponse } from '@/tools/jsm/types'
|
||||
import { TRANSITION_ITEM_PROPERTIES } from '@/tools/jsm/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const jsmGetTransitionsTool: ToolConfig<JsmGetTransitionsParams, JsmGetTransitionsResponse> =
|
||||
{
|
||||
id: 'jsm_get_transitions',
|
||||
name: 'JSM Get Transitions',
|
||||
description: 'Get available transitions for a service request in Jira Service Management',
|
||||
version: '1.0.0',
|
||||
|
||||
oauth: {
|
||||
required: true,
|
||||
provider: 'jira',
|
||||
},
|
||||
|
||||
params: {
|
||||
accessToken: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'hidden',
|
||||
description: 'OAuth access token for Jira Service Management',
|
||||
},
|
||||
domain: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Your Jira domain (e.g., yourcompany.atlassian.net)',
|
||||
},
|
||||
cloudId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'hidden',
|
||||
description: 'Jira Cloud ID for the instance',
|
||||
},
|
||||
issueIdOrKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Issue ID or key (e.g., SD-123)',
|
||||
},
|
||||
start: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Start index for pagination (e.g., 0, 50, 100)',
|
||||
},
|
||||
limit: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Maximum results to return (e.g., 10, 25, 50)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: '/api/tools/jsm/transitions',
|
||||
method: 'POST',
|
||||
headers: () => ({
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
body: (params) => ({
|
||||
domain: params.domain,
|
||||
accessToken: params.accessToken,
|
||||
cloudId: params.cloudId,
|
||||
issueIdOrKey: params.issueIdOrKey,
|
||||
start: params.start,
|
||||
limit: params.limit,
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const responseText = await response.text()
|
||||
|
||||
if (!responseText) {
|
||||
return {
|
||||
success: false,
|
||||
output: {
|
||||
ts: new Date().toISOString(),
|
||||
issueIdOrKey: '',
|
||||
transitions: [],
|
||||
total: 0,
|
||||
isLastPage: true,
|
||||
},
|
||||
error: 'Empty response from API',
|
||||
}
|
||||
}
|
||||
|
||||
const data = JSON.parse(responseText)
|
||||
|
||||
if (data.success && data.output) {
|
||||
return data
|
||||
}
|
||||
|
||||
return {
|
||||
success: data.success || false,
|
||||
output: data.output || {
|
||||
ts: new Date().toISOString(),
|
||||
issueIdOrKey: '',
|
||||
transitions: [],
|
||||
total: 0,
|
||||
isLastPage: true,
|
||||
},
|
||||
error: data.error,
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
ts: { type: 'string', description: 'Timestamp of the operation' },
|
||||
issueIdOrKey: { type: 'string', description: 'Issue ID or key' },
|
||||
transitions: {
|
||||
type: 'array',
|
||||
description: 'List of available transitions',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: TRANSITION_ITEM_PROPERTIES,
|
||||
},
|
||||
},
|
||||
total: { type: 'number', description: 'Total number of transitions' },
|
||||
isLastPage: { type: 'boolean', description: 'Whether this is the last page' },
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
import { jsmAddCommentTool } from '@/tools/jsm/add_comment'
|
||||
import { jsmAddCustomerTool } from '@/tools/jsm/add_customer'
|
||||
import { jsmAddOrganizationTool } from '@/tools/jsm/add_organization'
|
||||
import { jsmAddParticipantsTool } from '@/tools/jsm/add_participants'
|
||||
import { jsmAnswerApprovalTool } from '@/tools/jsm/answer_approval'
|
||||
import { jsmAttachFormTool } from '@/tools/jsm/attach_form'
|
||||
import { jsmCopyFormsTool } from '@/tools/jsm/copy_forms'
|
||||
import { jsmCreateObjectTool } from '@/tools/jsm/create_object'
|
||||
import { jsmCreateOrganizationTool } from '@/tools/jsm/create_organization'
|
||||
import { jsmCreateRequestTool } from '@/tools/jsm/create_request'
|
||||
import { jsmDeleteFormTool } from '@/tools/jsm/delete_form'
|
||||
import { jsmDeleteObjectTool } from '@/tools/jsm/delete_object'
|
||||
import { jsmExternaliseFormTool } from '@/tools/jsm/externalise_form'
|
||||
import { jsmGetApprovalsTool } from '@/tools/jsm/get_approvals'
|
||||
import { jsmGetCommentsTool } from '@/tools/jsm/get_comments'
|
||||
import { jsmGetCustomersTool } from '@/tools/jsm/get_customers'
|
||||
import { jsmGetFormTool } from '@/tools/jsm/get_form'
|
||||
import { jsmGetFormAnswersTool } from '@/tools/jsm/get_form_answers'
|
||||
import { jsmGetFormStructureTool } from '@/tools/jsm/get_form_structure'
|
||||
import { jsmGetFormTemplatesTool } from '@/tools/jsm/get_form_templates'
|
||||
import { jsmGetIssueFormsTool } from '@/tools/jsm/get_issue_forms'
|
||||
import { jsmGetObjectTool } from '@/tools/jsm/get_object'
|
||||
import { jsmGetObjectSchemaTool } from '@/tools/jsm/get_object_schema'
|
||||
import { jsmGetObjectTypeAttributesTool } from '@/tools/jsm/get_object_type_attributes'
|
||||
import { jsmGetOrganizationsTool } from '@/tools/jsm/get_organizations'
|
||||
import { jsmGetParticipantsTool } from '@/tools/jsm/get_participants'
|
||||
import { jsmGetQueuesTool } from '@/tools/jsm/get_queues'
|
||||
import { jsmGetRequestTool } from '@/tools/jsm/get_request'
|
||||
import { jsmGetRequestTypeFieldsTool } from '@/tools/jsm/get_request_type_fields'
|
||||
import { jsmGetRequestTypesTool } from '@/tools/jsm/get_request_types'
|
||||
import { jsmGetRequestsTool } from '@/tools/jsm/get_requests'
|
||||
import { jsmGetServiceDesksTool } from '@/tools/jsm/get_service_desks'
|
||||
import { jsmGetSlaTool } from '@/tools/jsm/get_sla'
|
||||
import { jsmGetTransitionsTool } from '@/tools/jsm/get_transitions'
|
||||
import { jsmInternaliseFormTool } from '@/tools/jsm/internalise_form'
|
||||
import { jsmListObjectSchemasTool } from '@/tools/jsm/list_object_schemas'
|
||||
import { jsmListObjectTypesTool } from '@/tools/jsm/list_object_types'
|
||||
import { jsmReopenFormTool } from '@/tools/jsm/reopen_form'
|
||||
import { jsmSaveFormAnswersTool } from '@/tools/jsm/save_form_answers'
|
||||
import { jsmSearchObjectsAqlTool } from '@/tools/jsm/search_objects_aql'
|
||||
import { jsmSubmitFormTool } from '@/tools/jsm/submit_form'
|
||||
import { jsmTransitionRequestTool } from '@/tools/jsm/transition_request'
|
||||
import { jsmUpdateObjectTool } from '@/tools/jsm/update_object'
|
||||
|
||||
export {
|
||||
jsmAddCommentTool,
|
||||
jsmAddCustomerTool,
|
||||
jsmAddOrganizationTool,
|
||||
jsmAddParticipantsTool,
|
||||
jsmAnswerApprovalTool,
|
||||
jsmAttachFormTool,
|
||||
jsmCopyFormsTool,
|
||||
jsmCreateObjectTool,
|
||||
jsmCreateOrganizationTool,
|
||||
jsmCreateRequestTool,
|
||||
jsmDeleteFormTool,
|
||||
jsmDeleteObjectTool,
|
||||
jsmExternaliseFormTool,
|
||||
jsmGetApprovalsTool,
|
||||
jsmGetCommentsTool,
|
||||
jsmGetCustomersTool,
|
||||
jsmGetFormTool,
|
||||
jsmGetFormAnswersTool,
|
||||
jsmGetFormStructureTool,
|
||||
jsmGetFormTemplatesTool,
|
||||
jsmGetIssueFormsTool,
|
||||
jsmGetObjectTool,
|
||||
jsmGetObjectSchemaTool,
|
||||
jsmGetObjectTypeAttributesTool,
|
||||
jsmGetOrganizationsTool,
|
||||
jsmGetParticipantsTool,
|
||||
jsmGetQueuesTool,
|
||||
jsmGetRequestTool,
|
||||
jsmGetRequestTypeFieldsTool,
|
||||
jsmGetRequestsTool,
|
||||
jsmGetRequestTypesTool,
|
||||
jsmGetServiceDesksTool,
|
||||
jsmGetSlaTool,
|
||||
jsmGetTransitionsTool,
|
||||
jsmInternaliseFormTool,
|
||||
jsmListObjectSchemasTool,
|
||||
jsmListObjectTypesTool,
|
||||
jsmReopenFormTool,
|
||||
jsmSaveFormAnswersTool,
|
||||
jsmSearchObjectsAqlTool,
|
||||
jsmSubmitFormTool,
|
||||
jsmTransitionRequestTool,
|
||||
jsmUpdateObjectTool,
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
import type { JsmInternaliseFormParams, JsmInternaliseFormResponse } from '@/tools/jsm/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const jsmInternaliseFormTool: ToolConfig<
|
||||
JsmInternaliseFormParams,
|
||||
JsmInternaliseFormResponse
|
||||
> = {
|
||||
id: 'jsm_internalise_form',
|
||||
name: 'JSM Internalise Form',
|
||||
description:
|
||||
'Make a form internal only (not visible to customers) on a Jira issue or JSM request',
|
||||
version: '1.0.0',
|
||||
oauth: { required: true, provider: 'jira' },
|
||||
params: {
|
||||
accessToken: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'hidden',
|
||||
description: 'OAuth access token for Jira Service Management',
|
||||
},
|
||||
domain: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Your Jira domain (e.g., yourcompany.atlassian.net)',
|
||||
},
|
||||
cloudId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'hidden',
|
||||
description: 'Jira Cloud ID for the instance',
|
||||
},
|
||||
issueIdOrKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Issue ID or key (e.g., "SD-123")',
|
||||
},
|
||||
formId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Form instance UUID',
|
||||
},
|
||||
},
|
||||
request: {
|
||||
url: '/api/tools/jsm/forms/internalise',
|
||||
method: 'POST',
|
||||
headers: () => ({ 'Content-Type': 'application/json' }),
|
||||
body: (params) => ({
|
||||
domain: params.domain,
|
||||
accessToken: params.accessToken,
|
||||
cloudId: params.cloudId,
|
||||
issueIdOrKey: params.issueIdOrKey,
|
||||
formId: params.formId,
|
||||
}),
|
||||
},
|
||||
transformResponse: async (response: Response) => {
|
||||
const responseText = await response.text()
|
||||
if (!responseText) {
|
||||
return {
|
||||
success: false,
|
||||
output: { ts: new Date().toISOString(), issueIdOrKey: '', formId: '', visibility: '' },
|
||||
error: 'Empty response from API',
|
||||
}
|
||||
}
|
||||
const data = JSON.parse(responseText)
|
||||
if (data.success && data.output) return data
|
||||
return {
|
||||
success: data.success || false,
|
||||
output: data.output || {
|
||||
ts: new Date().toISOString(),
|
||||
issueIdOrKey: '',
|
||||
formId: '',
|
||||
visibility: '',
|
||||
},
|
||||
error: data.error,
|
||||
}
|
||||
},
|
||||
outputs: {
|
||||
ts: { type: 'string', description: 'Timestamp of the operation' },
|
||||
issueIdOrKey: { type: 'string', description: 'Issue ID or key' },
|
||||
formId: { type: 'string', description: 'Form instance UUID' },
|
||||
visibility: {
|
||||
type: 'string',
|
||||
description: 'Form visibility after change (internal or external)',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
import type { JsmListObjectSchemasParams, JsmListObjectSchemasResponse } from '@/tools/jsm/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const jsmListObjectSchemasTool: ToolConfig<
|
||||
JsmListObjectSchemasParams,
|
||||
JsmListObjectSchemasResponse
|
||||
> = {
|
||||
id: 'jsm_list_object_schemas',
|
||||
name: 'JSM List Asset Schemas',
|
||||
description: 'List Assets (Insight/CMDB) object schemas in Jira Service Management',
|
||||
version: '1.0.0',
|
||||
|
||||
oauth: {
|
||||
required: true,
|
||||
provider: 'jira',
|
||||
},
|
||||
|
||||
params: {
|
||||
accessToken: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'hidden',
|
||||
description: 'OAuth access token for Jira Service Management',
|
||||
},
|
||||
domain: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Your Jira domain (e.g., yourcompany.atlassian.net)',
|
||||
},
|
||||
cloudId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'hidden',
|
||||
description: 'Jira Cloud ID for the instance',
|
||||
},
|
||||
workspaceId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'hidden',
|
||||
description: 'Assets workspace ID (resolved automatically when omitted)',
|
||||
},
|
||||
startAt: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Pagination start index (e.g., 0, 50)',
|
||||
},
|
||||
maxResults: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Maximum schemas to return (e.g., 25, 50)',
|
||||
},
|
||||
includeCounts: {
|
||||
type: 'boolean',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Include object and object-type counts per schema',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: '/api/tools/jsm/assets/schemas',
|
||||
method: 'POST',
|
||||
headers: () => ({ 'Content-Type': 'application/json' }),
|
||||
body: (params) => ({
|
||||
domain: params.domain,
|
||||
accessToken: params.accessToken,
|
||||
cloudId: params.cloudId,
|
||||
workspaceId: params.workspaceId,
|
||||
startAt: params.startAt,
|
||||
maxResults: params.maxResults,
|
||||
includeCounts: params.includeCounts,
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const responseText = await response.text()
|
||||
if (!responseText) {
|
||||
return {
|
||||
success: false,
|
||||
output: { ts: new Date().toISOString(), schemas: [], total: 0, isLast: true },
|
||||
error: 'Empty response from API',
|
||||
}
|
||||
}
|
||||
const data = JSON.parse(responseText)
|
||||
if (data.success && data.output) return data
|
||||
return {
|
||||
success: data.success || false,
|
||||
output: data.output || {
|
||||
ts: new Date().toISOString(),
|
||||
schemas: [],
|
||||
total: 0,
|
||||
isLast: true,
|
||||
},
|
||||
error: data.error,
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
ts: { type: 'string', description: 'Timestamp of the operation' },
|
||||
schemas: {
|
||||
type: 'array',
|
||||
description: 'List of Assets object schemas',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: { type: 'string', description: 'Schema ID' },
|
||||
name: { type: 'string', description: 'Schema name' },
|
||||
objectSchemaKey: { type: 'string', description: 'Schema key' },
|
||||
status: { type: 'string', description: 'Schema status' },
|
||||
description: { type: 'string', description: 'Schema description', optional: true },
|
||||
objectCount: { type: 'number', description: 'Number of objects', optional: true },
|
||||
objectTypeCount: {
|
||||
type: 'number',
|
||||
description: 'Number of object types',
|
||||
optional: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
total: { type: 'number', description: 'Total number of schemas' },
|
||||
isLast: { type: 'boolean', description: 'Whether this is the last page' },
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
import type { JsmListObjectTypesParams, JsmListObjectTypesResponse } from '@/tools/jsm/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const jsmListObjectTypesTool: ToolConfig<
|
||||
JsmListObjectTypesParams,
|
||||
JsmListObjectTypesResponse
|
||||
> = {
|
||||
id: 'jsm_list_object_types',
|
||||
name: 'JSM List Asset Object Types',
|
||||
description: 'List object types within an Assets (Insight/CMDB) object schema',
|
||||
version: '1.0.0',
|
||||
|
||||
oauth: {
|
||||
required: true,
|
||||
provider: 'jira',
|
||||
},
|
||||
|
||||
params: {
|
||||
accessToken: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'hidden',
|
||||
description: 'OAuth access token for Jira Service Management',
|
||||
},
|
||||
domain: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Your Jira domain (e.g., yourcompany.atlassian.net)',
|
||||
},
|
||||
cloudId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'hidden',
|
||||
description: 'Jira Cloud ID for the instance',
|
||||
},
|
||||
workspaceId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'hidden',
|
||||
description: 'Assets workspace ID (resolved automatically when omitted)',
|
||||
},
|
||||
schemaId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'The Assets object schema ID to list object types for',
|
||||
},
|
||||
excludeAbstract: {
|
||||
type: 'boolean',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Exclude abstract object types from the result',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: '/api/tools/jsm/assets/object-types',
|
||||
method: 'POST',
|
||||
headers: () => ({ 'Content-Type': 'application/json' }),
|
||||
body: (params) => ({
|
||||
domain: params.domain,
|
||||
accessToken: params.accessToken,
|
||||
cloudId: params.cloudId,
|
||||
workspaceId: params.workspaceId,
|
||||
schemaId: params.schemaId?.trim(),
|
||||
excludeAbstract: params.excludeAbstract,
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const responseText = await response.text()
|
||||
if (!responseText) {
|
||||
return {
|
||||
success: false,
|
||||
output: { ts: new Date().toISOString(), objectTypes: [], total: 0 },
|
||||
error: 'Empty response from API',
|
||||
}
|
||||
}
|
||||
const data = JSON.parse(responseText)
|
||||
if (data.success && data.output) return data
|
||||
return {
|
||||
success: data.success || false,
|
||||
output: data.output || { ts: new Date().toISOString(), objectTypes: [], total: 0 },
|
||||
error: data.error,
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
ts: { type: 'string', description: 'Timestamp of the operation' },
|
||||
objectTypes: {
|
||||
type: 'array',
|
||||
description: 'List of object types in the schema',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: { type: 'string', description: 'Object type ID' },
|
||||
name: { type: 'string', description: 'Object type name' },
|
||||
description: { type: 'string', description: 'Object type description', optional: true },
|
||||
objectSchemaId: { type: 'string', description: 'Parent schema ID' },
|
||||
objectCount: { type: 'number', description: 'Number of objects', optional: true },
|
||||
abstractObjectType: {
|
||||
type: 'boolean',
|
||||
description: 'Whether the type is abstract',
|
||||
optional: true,
|
||||
},
|
||||
inherited: {
|
||||
type: 'boolean',
|
||||
description: 'Whether the type inherits attributes',
|
||||
optional: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
total: { type: 'number', description: 'Total number of object types' },
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
import type { JsmReopenFormParams, JsmReopenFormResponse } from '@/tools/jsm/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const jsmReopenFormTool: ToolConfig<JsmReopenFormParams, JsmReopenFormResponse> = {
|
||||
id: 'jsm_reopen_form',
|
||||
name: 'JSM Reopen Form',
|
||||
description: 'Reopen a submitted form on a Jira issue or JSM request, allowing further edits',
|
||||
version: '1.0.0',
|
||||
|
||||
oauth: {
|
||||
required: true,
|
||||
provider: 'jira',
|
||||
},
|
||||
|
||||
params: {
|
||||
accessToken: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'hidden',
|
||||
description: 'OAuth access token for Jira Service Management',
|
||||
},
|
||||
domain: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Your Jira domain (e.g., yourcompany.atlassian.net)',
|
||||
},
|
||||
cloudId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'hidden',
|
||||
description: 'Jira Cloud ID for the instance',
|
||||
},
|
||||
issueIdOrKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Issue ID or key (e.g., "SD-123")',
|
||||
},
|
||||
formId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Form instance UUID (from Get Issue Forms)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: '/api/tools/jsm/forms/reopen',
|
||||
method: 'POST',
|
||||
headers: () => ({
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
body: (params) => ({
|
||||
domain: params.domain,
|
||||
accessToken: params.accessToken,
|
||||
cloudId: params.cloudId,
|
||||
issueIdOrKey: params.issueIdOrKey,
|
||||
formId: params.formId,
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const responseText = await response.text()
|
||||
|
||||
if (!responseText) {
|
||||
return {
|
||||
success: false,
|
||||
output: {
|
||||
ts: new Date().toISOString(),
|
||||
issueIdOrKey: '',
|
||||
formId: '',
|
||||
status: '',
|
||||
},
|
||||
error: 'Empty response from API',
|
||||
}
|
||||
}
|
||||
|
||||
const data = JSON.parse(responseText)
|
||||
|
||||
if (data.success && data.output) {
|
||||
return data
|
||||
}
|
||||
|
||||
return {
|
||||
success: data.success || false,
|
||||
output: data.output || {
|
||||
ts: new Date().toISOString(),
|
||||
issueIdOrKey: '',
|
||||
formId: '',
|
||||
status: '',
|
||||
},
|
||||
error: data.error,
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
ts: { type: 'string', description: 'Timestamp of the operation' },
|
||||
issueIdOrKey: { type: 'string', description: 'Issue ID or key' },
|
||||
formId: { type: 'string', description: 'Form instance UUID' },
|
||||
status: {
|
||||
type: 'string',
|
||||
description: 'Form status after reopening (open, submitted, locked)',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
import type { JsmSaveFormAnswersParams, JsmSaveFormAnswersResponse } from '@/tools/jsm/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const jsmSaveFormAnswersTool: ToolConfig<
|
||||
JsmSaveFormAnswersParams,
|
||||
JsmSaveFormAnswersResponse
|
||||
> = {
|
||||
id: 'jsm_save_form_answers',
|
||||
name: 'JSM Save Form Answers',
|
||||
description: 'Save answers to a form attached to a Jira issue or JSM request',
|
||||
version: '1.0.0',
|
||||
|
||||
oauth: {
|
||||
required: true,
|
||||
provider: 'jira',
|
||||
},
|
||||
|
||||
params: {
|
||||
accessToken: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'hidden',
|
||||
description: 'OAuth access token for Jira Service Management',
|
||||
},
|
||||
domain: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Your Jira domain (e.g., yourcompany.atlassian.net)',
|
||||
},
|
||||
cloudId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'hidden',
|
||||
description: 'Jira Cloud ID for the instance',
|
||||
},
|
||||
issueIdOrKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Issue ID or key (e.g., "SD-123")',
|
||||
},
|
||||
formId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Form instance UUID (from Attach Form or Get Issue Forms)',
|
||||
},
|
||||
answers: {
|
||||
type: 'json',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description:
|
||||
'Form answers using numeric question IDs as keys (e.g., {"1": {"text": "Title"}, "4": {"choices": ["5"]}})',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: '/api/tools/jsm/forms/save',
|
||||
method: 'POST',
|
||||
headers: () => ({
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
body: (params) => ({
|
||||
domain: params.domain,
|
||||
accessToken: params.accessToken,
|
||||
cloudId: params.cloudId,
|
||||
issueIdOrKey: params.issueIdOrKey,
|
||||
formId: params.formId,
|
||||
answers: params.answers,
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const responseText = await response.text()
|
||||
|
||||
if (!responseText) {
|
||||
return {
|
||||
success: false,
|
||||
output: {
|
||||
ts: new Date().toISOString(),
|
||||
issueIdOrKey: '',
|
||||
formId: '',
|
||||
state: null,
|
||||
updated: null,
|
||||
},
|
||||
error: 'Empty response from API',
|
||||
}
|
||||
}
|
||||
|
||||
const data = JSON.parse(responseText)
|
||||
|
||||
if (data.success && data.output) {
|
||||
return data
|
||||
}
|
||||
|
||||
return {
|
||||
success: data.success || false,
|
||||
output: data.output || {
|
||||
ts: new Date().toISOString(),
|
||||
issueIdOrKey: '',
|
||||
formId: '',
|
||||
state: null,
|
||||
updated: null,
|
||||
},
|
||||
error: data.error,
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
ts: { type: 'string', description: 'Timestamp of the operation' },
|
||||
issueIdOrKey: { type: 'string', description: 'Issue ID or key' },
|
||||
formId: { type: 'string', description: 'Form instance UUID' },
|
||||
state: {
|
||||
type: 'json',
|
||||
description: 'Form state with status (open, submitted, locked)',
|
||||
optional: true,
|
||||
},
|
||||
updated: { type: 'string', description: 'Last updated timestamp', optional: true },
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,150 @@
|
||||
import type { JsmSearchObjectsAqlParams, JsmSearchObjectsAqlResponse } from '@/tools/jsm/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const jsmSearchObjectsAqlTool: ToolConfig<
|
||||
JsmSearchObjectsAqlParams,
|
||||
JsmSearchObjectsAqlResponse
|
||||
> = {
|
||||
id: 'jsm_search_objects_aql',
|
||||
name: 'JSM Search Assets (AQL)',
|
||||
description:
|
||||
'Search Assets (Insight/CMDB) objects using AQL (Assets Query Language), e.g. objectType = "Host" AND Status = "Running". Supports pagination.',
|
||||
version: '1.0.0',
|
||||
|
||||
oauth: {
|
||||
required: true,
|
||||
provider: 'jira',
|
||||
},
|
||||
|
||||
params: {
|
||||
accessToken: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'hidden',
|
||||
description: 'OAuth access token for Jira Service Management',
|
||||
},
|
||||
domain: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Your Jira domain (e.g., yourcompany.atlassian.net)',
|
||||
},
|
||||
cloudId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'hidden',
|
||||
description: 'Jira Cloud ID for the instance',
|
||||
},
|
||||
workspaceId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'hidden',
|
||||
description: 'Assets workspace ID (resolved automatically when omitted)',
|
||||
},
|
||||
qlQuery: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'AQL query string (e.g., objectType = "Host" AND "Operating System" = "Ubuntu")',
|
||||
},
|
||||
page: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Page number (1-based, defaults to 1)',
|
||||
},
|
||||
resultsPerPage: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Results per page (e.g., 25, 50)',
|
||||
},
|
||||
includeAttributes: {
|
||||
type: 'boolean',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Include resolved attribute values on each object (defaults to true)',
|
||||
},
|
||||
objectTypeId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Optionally scope the search to a single object type ID',
|
||||
},
|
||||
objectSchemaId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Optionally scope the search to a single object schema ID',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: '/api/tools/jsm/assets/search',
|
||||
method: 'POST',
|
||||
headers: () => ({ 'Content-Type': 'application/json' }),
|
||||
body: (params) => ({
|
||||
domain: params.domain,
|
||||
accessToken: params.accessToken,
|
||||
cloudId: params.cloudId,
|
||||
workspaceId: params.workspaceId,
|
||||
qlQuery: params.qlQuery,
|
||||
page: params.page,
|
||||
resultsPerPage: params.resultsPerPage,
|
||||
includeAttributes: params.includeAttributes,
|
||||
objectTypeId: params.objectTypeId,
|
||||
objectSchemaId: params.objectSchemaId,
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const responseText = await response.text()
|
||||
if (!responseText) {
|
||||
return {
|
||||
success: false,
|
||||
output: {
|
||||
ts: new Date().toISOString(),
|
||||
objects: [],
|
||||
total: 0,
|
||||
pageNumber: 0,
|
||||
pageSize: 0,
|
||||
},
|
||||
error: 'Empty response from API',
|
||||
}
|
||||
}
|
||||
const data = JSON.parse(responseText)
|
||||
if (data.success && data.output) return data
|
||||
return {
|
||||
success: data.success || false,
|
||||
output: data.output || {
|
||||
ts: new Date().toISOString(),
|
||||
objects: [],
|
||||
total: 0,
|
||||
pageNumber: 0,
|
||||
pageSize: 0,
|
||||
},
|
||||
error: data.error,
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
ts: { type: 'string', description: 'Timestamp of the operation' },
|
||||
objects: {
|
||||
type: 'array',
|
||||
description: 'Matching Assets objects',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: { type: 'string', description: 'Object ID' },
|
||||
label: { type: 'string', description: 'Object label', optional: true },
|
||||
objectKey: { type: 'string', description: 'Object key (e.g., HOST-123)', optional: true },
|
||||
objectType: { type: 'json', description: 'Object type metadata', optional: true },
|
||||
attributes: { type: 'json', description: 'Resolved attribute values', optional: true },
|
||||
},
|
||||
},
|
||||
},
|
||||
total: { type: 'number', description: 'Total number of matching objects (totalFilterCount)' },
|
||||
pageNumber: { type: 'number', description: 'Current page number' },
|
||||
pageSize: { type: 'number', description: 'Number of objects on this page' },
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
import type { JsmSubmitFormParams, JsmSubmitFormResponse } from '@/tools/jsm/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const jsmSubmitFormTool: ToolConfig<JsmSubmitFormParams, JsmSubmitFormResponse> = {
|
||||
id: 'jsm_submit_form',
|
||||
name: 'JSM Submit Form',
|
||||
description: 'Submit a form on a Jira issue or JSM request, locking it from further edits',
|
||||
version: '1.0.0',
|
||||
|
||||
oauth: {
|
||||
required: true,
|
||||
provider: 'jira',
|
||||
},
|
||||
|
||||
params: {
|
||||
accessToken: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'hidden',
|
||||
description: 'OAuth access token for Jira Service Management',
|
||||
},
|
||||
domain: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Your Jira domain (e.g., yourcompany.atlassian.net)',
|
||||
},
|
||||
cloudId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'hidden',
|
||||
description: 'Jira Cloud ID for the instance',
|
||||
},
|
||||
issueIdOrKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Issue ID or key (e.g., "SD-123")',
|
||||
},
|
||||
formId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Form instance UUID (from Attach Form or Get Issue Forms)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: '/api/tools/jsm/forms/submit',
|
||||
method: 'POST',
|
||||
headers: () => ({
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
body: (params) => ({
|
||||
domain: params.domain,
|
||||
accessToken: params.accessToken,
|
||||
cloudId: params.cloudId,
|
||||
issueIdOrKey: params.issueIdOrKey,
|
||||
formId: params.formId,
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const responseText = await response.text()
|
||||
|
||||
if (!responseText) {
|
||||
return {
|
||||
success: false,
|
||||
output: {
|
||||
ts: new Date().toISOString(),
|
||||
issueIdOrKey: '',
|
||||
formId: '',
|
||||
status: '',
|
||||
},
|
||||
error: 'Empty response from API',
|
||||
}
|
||||
}
|
||||
|
||||
const data = JSON.parse(responseText)
|
||||
|
||||
if (data.success && data.output) {
|
||||
return data
|
||||
}
|
||||
|
||||
return {
|
||||
success: data.success || false,
|
||||
output: data.output || {
|
||||
ts: new Date().toISOString(),
|
||||
issueIdOrKey: '',
|
||||
formId: '',
|
||||
status: '',
|
||||
},
|
||||
error: data.error,
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
ts: { type: 'string', description: 'Timestamp of the operation' },
|
||||
issueIdOrKey: { type: 'string', description: 'Issue ID or key' },
|
||||
formId: { type: 'string', description: 'Form instance UUID' },
|
||||
status: {
|
||||
type: 'string',
|
||||
description: 'Form status after submission (open, submitted, locked)',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
import type { JsmTransitionRequestParams, JsmTransitionRequestResponse } from '@/tools/jsm/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const jsmTransitionRequestTool: ToolConfig<
|
||||
JsmTransitionRequestParams,
|
||||
JsmTransitionRequestResponse
|
||||
> = {
|
||||
id: 'jsm_transition_request',
|
||||
name: 'JSM Transition Request',
|
||||
description: 'Transition a service request to a new status in Jira Service Management',
|
||||
version: '1.0.0',
|
||||
|
||||
oauth: {
|
||||
required: true,
|
||||
provider: 'jira',
|
||||
},
|
||||
|
||||
params: {
|
||||
accessToken: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'hidden',
|
||||
description: 'OAuth access token for Jira Service Management',
|
||||
},
|
||||
domain: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Your Jira domain (e.g., yourcompany.atlassian.net)',
|
||||
},
|
||||
cloudId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'hidden',
|
||||
description: 'Jira Cloud ID for the instance',
|
||||
},
|
||||
issueIdOrKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Issue ID or key (e.g., SD-123)',
|
||||
},
|
||||
transitionId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Transition ID to apply',
|
||||
},
|
||||
comment: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Optional comment to add during transition',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: '/api/tools/jsm/transition',
|
||||
method: 'POST',
|
||||
headers: () => ({
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
body: (params) => ({
|
||||
domain: params.domain,
|
||||
accessToken: params.accessToken,
|
||||
cloudId: params.cloudId,
|
||||
issueIdOrKey: params.issueIdOrKey,
|
||||
transitionId: params.transitionId,
|
||||
comment: params.comment,
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const responseText = await response.text()
|
||||
|
||||
if (!responseText) {
|
||||
return {
|
||||
success: false,
|
||||
output: {
|
||||
ts: new Date().toISOString(),
|
||||
issueIdOrKey: '',
|
||||
transitionId: '',
|
||||
success: false,
|
||||
},
|
||||
error: 'Empty response from API',
|
||||
}
|
||||
}
|
||||
|
||||
const data = JSON.parse(responseText)
|
||||
|
||||
if (data.success && data.output) {
|
||||
return data
|
||||
}
|
||||
|
||||
return {
|
||||
success: data.success || false,
|
||||
output: data.output || {
|
||||
ts: new Date().toISOString(),
|
||||
issueIdOrKey: '',
|
||||
transitionId: '',
|
||||
success: false,
|
||||
},
|
||||
error: data.error,
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
ts: { type: 'string', description: 'Timestamp of the operation' },
|
||||
issueIdOrKey: { type: 'string', description: 'Issue ID or key' },
|
||||
transitionId: { type: 'string', description: 'Applied transition ID' },
|
||||
success: { type: 'boolean', description: 'Whether the transition was successful' },
|
||||
},
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,104 @@
|
||||
import type { JsmUpdateObjectParams, JsmUpdateObjectResponse } from '@/tools/jsm/types'
|
||||
import { ASSET_OBJECT_PROPERTIES } from '@/tools/jsm/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const jsmUpdateObjectTool: ToolConfig<JsmUpdateObjectParams, JsmUpdateObjectResponse> = {
|
||||
id: 'jsm_update_object',
|
||||
name: 'JSM Update Asset Object',
|
||||
description:
|
||||
'Update an existing Assets (Insight/CMDB) object. Provide the attributes to change using their objectTypeAttributeId values.',
|
||||
version: '1.0.0',
|
||||
|
||||
oauth: {
|
||||
required: true,
|
||||
provider: 'jira',
|
||||
},
|
||||
|
||||
params: {
|
||||
accessToken: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'hidden',
|
||||
description: 'OAuth access token for Jira Service Management',
|
||||
},
|
||||
domain: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Your Jira domain (e.g., yourcompany.atlassian.net)',
|
||||
},
|
||||
cloudId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'hidden',
|
||||
description: 'Jira Cloud ID for the instance',
|
||||
},
|
||||
workspaceId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'hidden',
|
||||
description: 'Assets workspace ID (resolved automatically when omitted)',
|
||||
},
|
||||
objectId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'The Assets object ID to update',
|
||||
},
|
||||
attributes: {
|
||||
type: 'json',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description:
|
||||
'Array of attributes to set: [{ objectTypeAttributeId, objectAttributeValues: [{ value }] }]',
|
||||
},
|
||||
objectTypeId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Optional object type ID (only if changing the type)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: '/api/tools/jsm/assets/object/update',
|
||||
method: 'POST',
|
||||
headers: () => ({ 'Content-Type': 'application/json' }),
|
||||
body: (params) => ({
|
||||
domain: params.domain,
|
||||
accessToken: params.accessToken,
|
||||
cloudId: params.cloudId,
|
||||
workspaceId: params.workspaceId,
|
||||
objectId: params.objectId?.trim(),
|
||||
objectTypeId: params.objectTypeId?.trim(),
|
||||
attributes: params.attributes,
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const responseText = await response.text()
|
||||
if (!responseText) {
|
||||
return {
|
||||
success: false,
|
||||
output: { ts: new Date().toISOString(), object: null },
|
||||
error: 'Empty response from API',
|
||||
}
|
||||
}
|
||||
const data = JSON.parse(responseText)
|
||||
if (data.success && data.output) return data
|
||||
return {
|
||||
success: data.success || false,
|
||||
output: data.output || { ts: new Date().toISOString(), object: null },
|
||||
error: data.error,
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
ts: { type: 'string', description: 'Timestamp of the operation' },
|
||||
object: {
|
||||
type: 'json',
|
||||
description: 'The updated Assets object',
|
||||
properties: ASSET_OBJECT_PROPERTIES,
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
/**
|
||||
* Shared utilities for Jira Service Management tools
|
||||
*/
|
||||
|
||||
import { getJiraCloudId } from '@/tools/jira/utils'
|
||||
import type { AssetObject, RawAssetObject } from '@/tools/jsm/types'
|
||||
|
||||
/**
|
||||
* Resolve the Jira `cloudId` and Assets `workspaceId` needed for an Assets API
|
||||
* call, using the request params when present and falling back to discovery.
|
||||
* @param domain - The Jira site domain
|
||||
* @param accessToken - The OAuth access token
|
||||
* @param cloudIdParam - Optional cloudId already supplied by the caller
|
||||
* @param workspaceIdParam - Optional workspaceId already supplied by the caller
|
||||
*/
|
||||
export async function resolveAssetsContext(
|
||||
domain: string,
|
||||
accessToken: string,
|
||||
cloudIdParam?: string,
|
||||
workspaceIdParam?: string
|
||||
): Promise<{ cloudId: string; workspaceId: string }> {
|
||||
const cloudId = cloudIdParam || (await getJiraCloudId(domain, accessToken))
|
||||
const workspaceId = workspaceIdParam || (await getAssetsWorkspaceId(cloudId, accessToken))
|
||||
return { cloudId, workspaceId }
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize a raw Assets object (from get/create/update) into the trimmed
|
||||
* {@link AssetObject} shape returned by the tools.
|
||||
* @param data - The raw object payload from the Assets API
|
||||
*/
|
||||
export function mapAssetObject(data: RawAssetObject): AssetObject {
|
||||
return {
|
||||
id: data.id,
|
||||
label: data.label ?? null,
|
||||
objectKey: data.objectKey ?? null,
|
||||
globalId: data.globalId ?? null,
|
||||
created: data.created ?? null,
|
||||
updated: data.updated ?? null,
|
||||
hasAvatar: data.hasAvatar ?? false,
|
||||
objectType: data.objectType ?? null,
|
||||
attributes: (data.attributes ?? []).map((attr) => ({
|
||||
id: attr.id ?? '',
|
||||
objectTypeAttributeId: attr.objectTypeAttributeId ?? '',
|
||||
objectAttributeValues: (attr.objectAttributeValues ?? []).map((v) => ({
|
||||
value: v.value ?? null,
|
||||
displayValue: v.displayValue ?? null,
|
||||
searchValue: v.searchValue ?? null,
|
||||
referencedType: v.referencedType ?? false,
|
||||
referencedObject: v.referencedObject ?? null,
|
||||
})),
|
||||
})),
|
||||
link: data._links?.self ?? null,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the base URL for JSM Service Desk API
|
||||
* @param cloudId - The Jira Cloud ID
|
||||
* @returns The base URL for the Service Desk API
|
||||
*/
|
||||
export function getJsmApiBaseUrl(cloudId: string): string {
|
||||
return `https://api.atlassian.com/ex/jira/${cloudId}/rest/servicedeskapi`
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the base URL for JSM Forms (ProForma) API
|
||||
* @param cloudId - The Jira Cloud ID
|
||||
* @returns The base URL for the JSM Forms API
|
||||
*/
|
||||
export function getJsmFormsApiBaseUrl(cloudId: string): string {
|
||||
return `https://api.atlassian.com/ex/jira/${cloudId}/forms`
|
||||
}
|
||||
|
||||
/**
|
||||
* Build common headers for JSM API requests
|
||||
* @param accessToken - The OAuth access token
|
||||
* @returns Headers object for API requests
|
||||
*/
|
||||
export function getJsmHeaders(accessToken: string): Record<string, string> {
|
||||
return {
|
||||
Authorization: `Bearer ${accessToken}`,
|
||||
Accept: 'application/json',
|
||||
'Content-Type': 'application/json',
|
||||
'X-ExperimentalApi': 'opt-in',
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the base URL for the JSM Assets (Insight/CMDB) API.
|
||||
*
|
||||
* Uses the OAuth 2.0 (3LO) gateway form `/ex/jira/{cloudId}/...` — matching
|
||||
* {@link getJsmApiBaseUrl} — keyed by both the Jira `cloudId` and the Assets
|
||||
* `workspaceId` (resolved via {@link getAssetsWorkspaceId}).
|
||||
* @param cloudId - The Jira Cloud ID
|
||||
* @param workspaceId - The Assets workspace ID
|
||||
* @returns The base URL for the Assets API (v1)
|
||||
*/
|
||||
export function getAssetsApiBaseUrl(cloudId: string, workspaceId: string): string {
|
||||
return `https://api.atlassian.com/ex/jira/${cloudId}/jsm/assets/workspace/${workspaceId}/v1`
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the Assets `workspaceId` for a Jira site.
|
||||
*
|
||||
* Calls the Service Desk discovery endpoint and uses the first workspace.
|
||||
* Atlassian provisions a single Assets workspace per site, so this is the
|
||||
* canonical workspace; callers on a multi-workspace site can pass an explicit
|
||||
* `workspaceId` to {@link resolveAssetsContext} to override it. Requires the
|
||||
* `read:servicedesk-request` scope (already granted by the `jira` provider).
|
||||
* @param cloudId - The Jira Cloud ID
|
||||
* @param accessToken - The OAuth access token
|
||||
* @returns The Assets workspace ID for the site
|
||||
* @throws If discovery fails or no workspace is provisioned
|
||||
*/
|
||||
export async function getAssetsWorkspaceId(cloudId: string, accessToken: string): Promise<string> {
|
||||
const response = await fetch(
|
||||
`https://api.atlassian.com/ex/jira/${cloudId}/rest/servicedeskapi/assets/workspace`,
|
||||
{ method: 'GET', headers: getJsmHeaders(accessToken) }
|
||||
)
|
||||
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text()
|
||||
throw new Error(
|
||||
`Failed to resolve Assets workspace: ${response.status} - ${errorText || response.statusText}`
|
||||
)
|
||||
}
|
||||
|
||||
const data = await response.json()
|
||||
const workspaceId: string | undefined = data?.values?.[0]?.workspaceId
|
||||
|
||||
if (!workspaceId) {
|
||||
throw new Error(
|
||||
'No Assets workspace found for this site. Assets (Insight) may not be enabled on the Jira instance.'
|
||||
)
|
||||
}
|
||||
|
||||
return workspaceId
|
||||
}
|
||||
Reference in New Issue
Block a user