Навык script-include-patterns
✓ ПровереноСоздание и управление Script Includes в ServiceNow с использованием Class.create, AbstractAjaxProcessor и паттернов наследования.
- Звёзды на GitHub
- 77
- Файлы
- 1
- Последний коммит
- 20 окт. 2026 г.
- Лицензия
- Apache-2.0
- Разрешённые инструменты
- —
Что делает навык script-include-patterns?
script-include-patterns — это Agent Skill. Создание и управление Script Includes в ServiceNow с использованием Class.create, AbstractAjaxProcessor и паттернов наследования.
Сводка сгенерирована из SKILL.md навыка.
О skill script-include-patterns
Основная задача этого SKILL — разработка переиспользуемых JavaScript-библиотек на стороне сервера для ServiceNow. Он помогает разработчикам писать и управлять различными типами Script Includes, включая стандартные утилиты, клиентские API для GlideAjax и классы с ленивой загрузкой (on-demand). SKILL поддерживает сложные архитектурные паттерны, такие как наследование через Object.extendsObject, и специфические реализации для scoped applications.
Агенту следует загрузить этот SKILL, когда разработчику необходимо создать или изменить логику ServiceNow. Он предоставляет специализированные инструменты для автоматизации жизненного цикла разработки, такие как snow_create_script_include для генерации новых классов, snow_artifact_manage для поиска или обновления существующего кода и snow_execute_script для тестирования логики. Соблюдение стандартов ES5 обеспечивает совместимость со средой ServiceNow и помогает поддерживать чистоту кода с помощью структурированных паттернов, таких как AbstractAjaxProcessor для взаимодействия клиента и сервера.
Что агент может делать с ним
- 1Создание клиентских APIРазработка класса, расширяющего AbstractAjaxProcessor, для обеспечения взаимодействия клиентских скриптов с сервером через GlideAjax.
- 2Реализация наследования классовСоздание производного класса, который наследует функциональность от базового класса утилит для задач (task utility class).
Написано на основе skill SKILL.md. Каждый сценарий использования проверен по цитате из него.
Как установить навык script-include-patterns
Каждая команда копирует папку навыка в каталог навыков клиента. Перезапустите клиент или начните новую сессию, чтобы загрузить его.Установка навыка script-include-patterns в Claude Code
~/.claude/skills/script-include-patterns/SKILL.md
$ npx degit serac-labs/serac/packages/skills/script-include-patterns ~/.claude/skills/script-include-patternsУстановка навыка script-include-patterns в Claude Code (project)
.claude/skills/script-include-patterns/SKILL.md
$ npx degit serac-labs/serac/packages/skills/script-include-patterns .claude/skills/script-include-patternsУстановка навыка script-include-patterns в Codex
~/.agents/skills/script-include-patterns/SKILL.md
$ npx degit serac-labs/serac/packages/skills/script-include-patterns ~/.agents/skills/script-include-patternsУстановка навыка script-include-patterns в Gemini CLI
~/.gemini/skills/script-include-patterns/SKILL.md
$ npx degit serac-labs/serac/packages/skills/script-include-patterns ~/.gemini/skills/script-include-patternsУстановка навыка script-include-patterns в Claude.ai
npx degit serac-labs/serac/packages/skills/script-include-patterns script-include-patterns && zip -r script-include-patterns.zip script-include-patterns # claude.ai → Customize → Skills → + → Create skill → Upload a skill → script-include-patterns.zip
Автоматические проверки
Запущено 14 нояб. 2026 г.Полный отчёт →Прошёл наши автоматические проверки. Это не аудит безопасности: прочитайте скрипты, прежде чем агент их запустит. Как работают проверки · Что исправить, чтобы получить больше баллов
- Связанный и доступный исходный репозиторийserac-labs/serac/packages/skills/script-include-patterns is public and reachablegithub.com/serac-labs/serac/tree/HEAD/packages/skills/script ↗Пройдено
- Open source лицензия (OSI)Apache-2.0spdx.org/licenses/Apache-2.0.html ↗Пройдено
- Коммит или релиз за последний годLast commit 2026-10-20github.com/serac-labs/serac/commits ↗Пройдено
- В скриптах нет загрузки с запуском и кражи учётных данныхNo scripts in the skill folderПройдено
- В SKILL.md нет скрытых инструкцийNo override phrases, safeguard switches, credential requests or hidden charactersgithub.com/serac-labs/serac/blob/HEAD/packages/skills/script ↗Пройдено
- Заранее разрешённые инструменты ограниченыNo pre-approved tools; the agent asks before using onegithub.com/serac-labs/serac/blob/HEAD/packages/skills/script ↗Пройдено
- SKILL.md соответствует формату Agent Skillsthe description does not say when to use the skillgithub.com/serac-labs/serac/blob/HEAD/packages/skills/script ↗Проблема
SKILL.md
Открыть на GitHubScript Include Patterns for ServiceNow
Script Includes are reusable server-side JavaScript libraries that can be called from any server-side script.
Script Include Types
| Type | Use Case | Client Callable |
|---|---|---|
| Standard | Server-side utilities | No |
| Client Callable | GlideAjax from client | Yes |
| On-Demand | Lazy loading | No |
| AbstractAjaxProcessor | Client-server communication | Yes |
Standard Script Include (ES5)
// Basic utility class
var IncidentUtils = Class.create()
IncidentUtils.prototype = {
initialize: function () {
this.LOG_PREFIX = "[IncidentUtils] "
},
/**
* Get incident by number
* @param {string} number - Incident number (INC0010001)
* @returns {GlideRecord|null} - Incident record or null
*/
getByNumber: function (number) {
var gr = new GlideRecord("incident")
gr.addQuery("number", number)
gr.query()
if (gr.next()) {
return gr
}
return null
},
/**
* Calculate priority based on impact and urgency
* @param {number} impact - Impact value (1-3)
* @param {number} urgency - Urgency value (1-3)
* @returns {number} - Calculated priority (1-5)
*/
calculatePriority: function (impact, urgency) {
var matrix = {
"1-1": 1,
"1-2": 2,
"1-3": 3,
"2-1": 2,
"2-2": 3,
"2-3": 4,
"3-1": 3,
"3-2": 4,
"3-3": 5,
}
var key = impact + "-" + urgency
return matrix[key] || 4
},
/**
* Get open incidents for user
* @param {string} userSysId - User sys_id
* @returns {Array} - Array of incident objects
*/
getOpenIncidentsForUser: function (userSysId) {
var incidents = []
var gr = new GlideRecord("incident")
gr.addQuery("caller_id", userSysId)
gr.addQuery("active", true)
gr.orderByDesc("opened_at")
gr.query()
while (gr.next()) {
incidents.push({
sys_id: gr.getUniqueValue(),
number: gr.getValue("number"),
short_description: gr.getValue("short_description"),
state: gr.state.getDisplayValue(),
priority: gr.priority.getDisplayValue(),
})
}
return incidents
},
type: "IncidentUtils",
}
Client Callable Script Include (ES5)
// Extends AbstractAjaxProcessor for GlideAjax calls
var IncidentAjax = Class.create()
IncidentAjax.prototype = Object.extendsObject(AbstractAjaxProcessor, {
/**
* Get incident details - callable from client
* Client calls: new GlideAjax('IncidentAjax').addParam('sysparm_name', 'getIncidentDetails')
*/
getIncidentDetails: function () {
var incidentId = this.getParameter("sysparm_incident_id")
var result = {}
var gr = new GlideRecord("incident")
if (gr.get(incidentId)) {
result.success = true
result.number = gr.getValue("number")
result.short_description = gr.getValue("short_description")
result.state = gr.state.getDisplayValue()
result.priority = gr.priority.getDisplayValue()
result.assigned_to = gr.assigned_to.getDisplayValue()
result.assignment_group = gr.assignment_group.getDisplayValue()
} else {
result.success = false
result.message = "Incident not found"
}
return JSON.stringify(result)
},
/**
* Search incidents by keyword
*/
searchIncidents: function () {
var keyword = this.getParameter("sysparm_keyword")
var limit = parseInt(this.getParameter("sysparm_limit"), 10) || 10
var incidents = []
var gr = new GlideRecord("incident")
gr.addQuery("short_description", "CONTAINS", keyword)
gr.addOrCondition("description", "CONTAINS", keyword)
gr.addQuery("active", true)
gr.setLimit(limit)
gr.orderByDesc("opened_at")
gr.query()
while (gr.next()) {
incidents.push({
sys_id: gr.getUniqueValue(),
number: gr.getValue("number"),
short_description: gr.getValue("short_description"),
})
}
return JSON.stringify(incidents)
},
/**
* Check if user can update incident
*/
canUserUpdate: function () {
var incidentId = this.getParameter("sysparm_incident_id")
var userId = gs.getUserID()
var gr = new GlideRecord("incident")
if (gr.get(incidentId)) {
// Check if user is assigned or in assignment group
var canUpdate =
gr.getValue("assigned_to") === userId || this._isUserInGroup(userId, gr.getValue("assignment_group"))
return JSON.stringify({ canUpdate: canUpdate })
}
return JSON.stringify({ canUpdate: false })
},
_isUserInGroup: function (userId, groupId) {
var member = new GlideRecord("sys_user_grmember")
member.addQuery("user", userId)
member.addQuery("group", groupId)
member.query()
return member.hasNext()
},
type: "IncidentAjax",
})
Client-Side GlideAjax Call (ES5)
// Client script calling Script Include
function getIncidentDetails(incidentSysId, callback) {
var ga = new GlideAjax("IncidentAjax")
ga.addParam("sysparm_name", "getIncidentDetails")
ga.addParam("sysparm_incident_id", incidentSysId)
ga.getXMLAnswer(function (answer) {
var result = JSON.parse(answer)
callback(result)
})
}
// Usage in client script
getIncidentDetails(g_form.getUniqueValue(), function (incident) {
if (incident.success) {
g_form.addInfoMessage("Incident: " + incident.number)
} else {
g_form.addErrorMessage(incident.message)
}
})
Inheritance Pattern (ES5)
// Base class
var TaskUtils = Class.create()
TaskUtils.prototype = {
initialize: function (tableName) {
this.tableName = tableName || "task"
},
getByState: function (state) {
var records = []
var gr = new GlideRecord(this.tableName)
gr.addQuery("state", state)
gr.query()
while (gr.next()) {
records.push(this._toObject(gr))
}
return records
},
_toObject: function (gr) {
return {
sys_id: gr.getUniqueValue(),
number: gr.getValue("number"),
short_description: gr.getValue("short_description"),
state: gr.getValue("state"),
}
},
type: "TaskUtils",
}
// Derived class
var IncidentUtilsExtended = Class.create()
IncidentUtilsExtended.prototype = Object.extendsObject(TaskUtils, {
initialize: function () {
TaskUtils.prototype.initialize.call(this, "incident")
},
getP1Incidents: function () {
var incidents = []
var gr = new GlideRecord("incident")
gr.addQuery("priority", 1)
gr.addQuery("active", true)
gr.query()
while (gr.next()) {
var obj = this._toObject(gr)
obj.caller = gr.caller_id.getDisplayValue()
incidents.push(obj)
}
return incidents
},
type: "IncidentUtilsExtended",
})
Scoped Script Include (ES5)
// In scoped application: x_myapp
var MyAppUtils = Class.create()
MyAppUtils.prototype = {
initialize: function () {
this.APP_SCOPE = "x_myapp"
},
/**
* Get application property
* @param {string} name - Property name (without scope prefix)
*/
getAppProperty: function (name) {
return gs.getProperty(this.APP_SCOPE + "." + name)
},
/**
* Log with application prefix
*/
log: function (message, source) {
gs.info("[" + this.APP_SCOPE + "][" + (source || "MyAppUtils") + "] " + message)
},
/**
* Access cross-scope table safely
*/
getGlobalUser: function (userId) {
var gr = new GlideRecord("sys_user")
if (gr.get(userId)) {
return {
name: gr.getValue("name"),
email: gr.getValue("email"),
}
}
return null
},
type: "MyAppUtils",
}
MCP Tool Integration
Available Script Include Tools
| Tool | Purpose |
|---|---|
snow_create_script_include |
Create new Script Include |
snow_artifact_manage (action='find') |
Find existing Script Includes |
snow_artifact_manage (action='update') |
Modify Script Include code |
snow_execute_script |
Test Script Include |
Example Workflow
// 1. Create Script Include
await snow_create_script_include({
name: "IncidentUtils",
script: "/* Script Include code */",
client_callable: false,
description: "Incident utility functions",
})
// 2. Test the Script Include
await snow_execute_script({
script: `
var utils = new IncidentUtils();
var incident = utils.getByNumber('INC0010001');
gs.info('Found: ' + (incident ? incident.number : 'null'));
`,
})
Best Practices
- Single Responsibility - One class, one purpose
- Meaningful Names - IncidentUtils not Utils
- Document Methods - JSDoc comments
- Error Handling - Try-catch with logging
- Private Methods - Prefix with underscore
- No Side Effects - Initialization should not modify data
- Testable - Write methods that can be unit tested
- ES5 Only - No const, let, arrow functions, template literals
Файлы в этом навыке
1Вопросы о навыке script-include-patterns
Как установить навык script-include-patterns в Claude Code?
Выполните npx degit serac-labs/serac/packages/skills/script-include-patterns ~/.claude/skills/script-include-patterns. Claude Code загружает навыки из ~/.claude/skills (все проекты) или .claude/skills (один проект) и использует навык, когда его описание соответствует задаче.
Какие клиенты могут использовать навык script-include-patterns?
Любой клиент, который читает формат Agent Skills: Claude Code, Codex, Gemini CLI и claude.ai (загрузить как ZIP). Скрипты в навыке выполняются только там, где клиент разрешает выполнение кода.
Какие типы Script Includes существуют в ServiceNow?
Script Includes могут быть стандартными (серверные утилиты), Client Callable (для GlideAjax), On-Demand (с ленивой загрузкой) или AbstractAjaxProcessor (для взаимодействия клиента и сервера).
Как реализовать наследование в Script Include в ServiceNow?
Вы можете использовать метод Object.extendsObject, чтобы производный класс мог наследоваться от базового класса।
Каким стандартам кодирования следует придерживаться при написании Script Includes?
Разработчикам следует использовать синтаксис ES5 (избегая const, let или стрелочных функций), придерживаться принципа единственной ответственности, использовать осмысленные имена и добавлять префикс нижнего подчеркивания к приватным методам.