重要前提
安装AI Skills的关键前提是:必须科学上网,且开启TUN模式,这一点至关重要,直接决定安装能否顺利完成,在此郑重提醒三遍:科学上网,科学上网,科学上网。查看完整安装教程 →
npx skills add https://github.com/groeimetai/snow-flow --skill scoped-apps限定范围应用为 ServiceNow 中的自定义开发提供了隔离性和可移植性。
| 特性 | 全局范围 | 限定范围应用 |
|---|---|---|
| 命名冲突 | 可能发生 | 可避免 (x_ 前缀) |
| 可移植性 | 困难 | 容易 (更新集) |
| 安全性 | 开放 | 受控 (跨范围) |
| 商店发布 | 不支持 | 支持 |
| 依赖关系 | 隐式 | 显式 |
1. 导航:系统应用 > Studio
2. 点击:创建应用
3. 输入:
- 名称:"我的自定义应用"
- 范围:"x_mycom_myapp" (自动生成)
- 版本:1.0.0
4. 配置:
- 运行时访问:勾选需要跨范围访问的表
snow_create_application({
name: "我的自定义应用",
scope: "x_mycom_custom",
version: "1.0.0",
description: "用于...的自定义应用",
})
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
x_[供应商]_[应用]
示例:
- x_acme_hr (ACME 公司人力资源应用)
- x_mycom_inventory (我的公司库存应用)
- x_snc_global (ServiceNow 全局应用)
// 限定范围表会自动添加前缀
// Studio 中的表名:"task_tracker"
// 实际表名:"x_mycom_myapp_task_tracker"
// 创建记录
var gr = new GlideRecord("x_mycom_myapp_task_tracker")
gr.initialize()
gr.setValue("name", "我的任务")
gr.insert()
var TaskManager = Class.create()
TaskManager.prototype = {
initialize: function () {
this.tableName = "x_mycom_myapp_task_tracker"
},
createTask: function (name, description) {
var gr = new GlideRecord(this.tableName)
gr.initialize()
gr.setValue("name", name)
gr.setValue("description", description)
return gr.insert()
},
// 标记为可从其他范围访问
// 要求:"可访问自:所有应用范围"
getTask: function (sysId) {
var gr = new GlideRecord(this.tableName)
if (gr.get(sysId)) {
return {
name: gr.getValue("name"),
description: gr.getValue("description"),
}
}
return null
},
type: "TaskManager",
}
// 从范围:x_mycom_otherapp
// 调用:x_mycom_myapp.TaskManager
// 选项 1:直接调用 (如果可访问)
var tm = new x_mycom_myapp.TaskManager()
var task = tm.getTask(sysId)
// 选项 2:GlideScopedEvaluator
var evaluator = new GlideScopedEvaluator()
evaluator.putVariable("sysId", sysId)
var result = evaluator.evaluateScript("x_mycom_myapp", "new TaskManager().getTask(sysId)")
// 检查是否允许跨范围访问
var gr = new GlideRecord("x_other_app_table")
if (!gr.isValid()) {
gs.error("无法访问 x_other_app_table")
return
}
// 如果可访问,正常查询
gr.addQuery("active", true)
gr.query()
// 在 应用 > 属性 中
// 名称:x_mycom_myapp.default_priority
// 值:3
// 类型:string
// 在 应用 > 模块 中
// 创建指向以下位置的"属性"模块:
// /sys_properties_list.do?sysparm_query=name=x_mycom_myapp
// 获取属性值
var defaultPriority = gs.getProperty("x_mycom_myapp.default_priority", "3")
// 设置属性值 (需要管理员权限)
gs.setProperty("x_mycom_myapp.default_priority", "2")
x_mycom_myapp/
├── 表
│ ├── x_mycom_myapp_task
│ └── x_mycom_myapp_config
├── 脚本包含
│ ├── TaskManager
│ └── ConfigUtils
├── 业务规则
│ └── 验证任务
├── UI 页面
│ └── task_dashboard
├── REST API
│ └── 任务 API
├── 计划作业
│ └── 每日清理
└── 应用属性
├── default_priority
└── enable_notifications
// 资源:/api/x_mycom_myapp/tasks
// HTTP 方法:GET
;(function process(request, response) {
var tasks = []
var gr = new GlideRecord("x_mycom_myapp_task_tracker")
gr.addQuery("active", true)
gr.query()
while (gr.next()) {
tasks.push({
sys_id: gr.getUniqueValue(),
name: gr.getValue("name"),
status: gr.getValue("status"),
})
}
response.setBody({
result: tasks,
count: tasks.length,
})
})(request, response)
curl -X GET \
"https://instance.service-now.com/api/x_mycom_myapp/tasks" \
-H "Authorization: Bearer token"
应用 > 依赖关系
添加:
- sn_hr_core (HR 核心)
- sn_cmdb (CMDB)
// 检查插件是否激活
if (GlidePluginManager.isActive("com.snc.hr.core")) {
// HR 核心可用
var hrCase = new sn_hr_core.hr_case()
}
□ 所有表都有适当的 ACL
□ 没有硬编码的 sys_id
□ 没有硬编码的实例 URL
□ 所有依赖关系已声明
□ 属性有默认值
□ 文档完整
□ 测试用例通过
□ 没有全局范围修改
□ 更新集在干净实例上测试过
主版本.次版本.修订版本
1.0.0 - 初始发布
1.1.0 - 新增功能
1.1.1 - 错误修复
2.0.0 - 重大变更
| 错误 | 问题 | 解决方案 |
|---|---|---|
| 全局修改 | 无法干净部署 | 将更改保持在范围内 |
| 硬编码 sys_id | 在其他实例上失败 | 使用属性或查找 |
| 缺少 ACL | 安全漏洞 | 为所有表创建 ACL |
| 没有错误处理 | 静默失败 | 添加 try/catch,日志记录 |
| 直接访问全局表 | 升级冲突 | 使用引用,而非副本 |
每周安装数
50
代码库
GitHub 星标数
58
首次出现
2026年1月22日
安全审计
安装于
claude-code46
github-copilot44
gemini-cli44
opencode44
codex44
cursor43
Scoped applications provide isolation and portability for custom development in ServiceNow.
| Feature | Global Scope | Scoped App |
|---|---|---|
| Naming conflicts | Possible | Prevented (x_prefix) |
| Portability | Difficult | Easy (Update Sets) |
| Security | Open | Controlled (Cross-scope) |
| Store publishing | No | Yes |
| Dependencies | Implicit | Explicit |
1. Navigate: System Applications > Studio
2. Click: Create Application
3. Enter:
- Name: "My Custom App"
- Scope: "x_mycom_myapp" (auto-generated)
- Version: 1.0.0
4. Configure:
- Runtime access: Check tables needing cross-scope access
snow_create_application({
name: "My Custom Application",
scope: "x_mycom_custom",
version: "1.0.0",
description: "Custom application for...",
})
x_[vendor]_[app]
Examples:
- x_acme_hr (ACME Corp HR App)
- x_mycom_inventory (My Company Inventory)
- x_snc_global (ServiceNow Global)
// Scoped tables are automatically prefixed
// Table name in Studio: "task_tracker"
// Actual table name: "x_mycom_myapp_task_tracker"
// Creating records
var gr = new GlideRecord("x_mycom_myapp_task_tracker")
gr.initialize()
gr.setValue("name", "My Task")
gr.insert()
var TaskManager = Class.create()
TaskManager.prototype = {
initialize: function () {
this.tableName = "x_mycom_myapp_task_tracker"
},
createTask: function (name, description) {
var gr = new GlideRecord(this.tableName)
gr.initialize()
gr.setValue("name", name)
gr.setValue("description", description)
return gr.insert()
},
// Mark as accessible from other scopes
// Requires: "Accessible from: All application scopes"
getTask: function (sysId) {
var gr = new GlideRecord(this.tableName)
if (gr.get(sysId)) {
return {
name: gr.getValue("name"),
description: gr.getValue("description"),
}
}
return null
},
type: "TaskManager",
}
// From scope: x_mycom_otherapp
// Calling: x_mycom_myapp.TaskManager
// Option 1: Direct call (if accessible)
var tm = new x_mycom_myapp.TaskManager()
var task = tm.getTask(sysId)
// Option 2: GlideScopedEvaluator
var evaluator = new GlideScopedEvaluator()
evaluator.putVariable("sysId", sysId)
var result = evaluator.evaluateScript("x_mycom_myapp", "new TaskManager().getTask(sysId)")
// Check if cross-scope access is allowed
var gr = new GlideRecord("x_other_app_table")
if (!gr.isValid()) {
gs.error("No access to x_other_app_table")
return
}
// If accessible, query normally
gr.addQuery("active", true)
gr.query()
// In Application > Properties
// Name: x_mycom_myapp.default_priority
// Value: 3
// Type: string
// In Application > Modules
// Create "Properties" module pointing to:
// /sys_properties_list.do?sysparm_query=name=x_mycom_myapp
// Get property value
var defaultPriority = gs.getProperty("x_mycom_myapp.default_priority", "3")
// Set property value (requires admin)
gs.setProperty("x_mycom_myapp.default_priority", "2")
x_mycom_myapp/
├── Tables
│ ├── x_mycom_myapp_task
│ └── x_mycom_myapp_config
├── Script Includes
│ ├── TaskManager
│ └── ConfigUtils
├── Business Rules
│ └── Validate Task
├── UI Pages
│ └── task_dashboard
├── REST API
│ └── Task API
├── Scheduled Jobs
│ └── Daily Cleanup
└── Application Properties
├── default_priority
└── enable_notifications
// Resource: /api/x_mycom_myapp/tasks
// HTTP Method: GET
;(function process(request, response) {
var tasks = []
var gr = new GlideRecord("x_mycom_myapp_task_tracker")
gr.addQuery("active", true)
gr.query()
while (gr.next()) {
tasks.push({
sys_id: gr.getUniqueValue(),
name: gr.getValue("name"),
status: gr.getValue("status"),
})
}
response.setBody({
result: tasks,
count: tasks.length,
})
})(request, response)
curl -X GET \
"https://instance.service-now.com/api/x_mycom_myapp/tasks" \
-H "Authorization: Bearer token"
Application > Dependencies
Add:
- sn_hr_core (HR Core)
- sn_cmdb (CMDB)
// Check if plugin is active
if (GlidePluginManager.isActive("com.snc.hr.core")) {
// HR Core is available
var hrCase = new sn_hr_core.hr_case()
}
□ All tables have proper ACLs
□ No hard-coded sys_ids
□ No hard-coded instance URLs
□ All dependencies declared
□ Properties have default values
□ Documentation complete
□ Test cases pass
□ No global scope modifications
□ Update Set tested on clean instance
Major.Minor.Patch
1.0.0 - Initial release
1.1.0 - New feature added
1.1.1 - Bug fix
2.0.0 - Breaking change
| Mistake | Problem | Solution |
|---|---|---|
| Global modifications | Won't deploy cleanly | Keep changes in scope |
| Hard-coded sys_ids | Fails on other instances | Use properties or lookups |
| Missing ACLs | Security vulnerabilities | Create ACLs for all tables |
| No error handling | Silent failures | Add try/catch, logging |
| Accessing global tables directly | Upgrade conflicts | Use references, not copies |
Weekly Installs
50
Repository
GitHub Stars
58
First Seen
Jan 22, 2026
Security Audits
Gen Agent Trust HubPassSocketPassSnykPass
Installed on
claude-code46
github-copilot44
gemini-cli44
opencode44
codex44
cursor43
Wix CLI 编排器指南:选择正确的扩展类型与自动化开发流程
281 周安装