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

This commit is contained in:
wehub-resource-sync
2026-07-13 13:20:55 +08:00
commit d25d482dc2
13754 changed files with 4996608 additions and 0 deletions
+132
View File
@@ -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' },
},
}
+100
View File
@@ -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' },
},
}
+107
View File
@@ -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' },
},
}
+115
View File
@@ -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' },
},
}
+163
View File
@@ -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' },
},
}
+122
View File
@@ -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,
},
},
}
+98
View File
@@ -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' },
},
}
+97
View File
@@ -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,
},
},
}
+100
View File
@@ -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' },
},
}
+184
View File
@@ -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' },
},
}
+82
View File
@@ -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' },
},
}
+84
View File
@@ -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' },
},
}
+88
View File
@@ -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)',
},
},
}
+122
View File
@@ -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' },
},
}
+142
View File
@@ -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' },
},
}
+125
View File
@@ -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' },
},
}
+122
View File
@@ -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,
},
},
}
+109
View File
@@ -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,
},
},
}
+121
View File
@@ -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,
},
},
}
+108
View File
@@ -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' },
},
}
+105
View File
@@ -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' },
},
}
+88
View File
@@ -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,
},
},
}
+102
View File
@@ -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' },
},
}
+121
View File
@@ -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' },
},
}
+125
View File
@@ -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' },
},
}
+125
View File
@@ -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' },
},
}
+152
View File
@@ -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,
},
},
},
}
+142
View File
@@ -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' },
},
}
+155
View File
@@ -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' },
},
}
+121
View File
@@ -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' },
},
}
+121
View File
@@ -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' },
},
}
+122
View File
@@ -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' },
},
}
+89
View File
@@ -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,
}
+89
View File
@@ -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)',
},
},
}
+126
View File
@@ -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' },
},
}
+117
View File
@@ -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' },
},
}
+106
View File
@@ -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)',
},
},
}
+121
View File
@@ -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 },
},
}
+150
View File
@@ -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' },
},
}
+106
View File
@@ -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)',
},
},
}
+113
View File
@@ -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
+104
View File
@@ -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,
},
},
}
+139
View File
@@ -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
}