Loading...
Loading...
Compare original and translation side by side
implement_appget_implementation_planidea_to_appfix_app_errorsfw-app-devget_developer_docsfdk validateimplement_appget_implementation_planidea_to_appfix_app_errorsfw-app-devget_developer_docsfdk validatefdkfw-setupskills/fw-setup/rules/smart-prerequisites-check.mdcnode --version 2>&1
fdk version 2>&1platform-versionengines.fdkengines.node| Installed Toolchain | Manifest State | Action |
|---|---|---|
| FDK 9.x / Node 18 | Platform 2.x manifest | STOP → |
| FDK 10.x / Node 24 | Platform 2.x manifest | STOP → |
| FDK 10.x / Node 24 | Platform 3.0 + engines match | ✅ PROCEED with task |
| FDK 10.x / Node 24 | Platform 3.0 + engines mismatch | Auto-update engines, clean deps, PROCEED |
| FDK 9.x / Node 18 | Platform 3.0 manifest | STOP → |
| Any | No manifest.json | Check toolchain only (new app) |
fdk validaterm -rf node_modules coverage .fdk && npm installsmart-prerequisites-check.mdcfw-setupskills/fw-setup//fw-setup-install/fw-setup-upgrade/fw-setup-use/fw-setup-statusfdk validatefdk runfdk packfw-setupfw-setupfw-setupskills/fw-setup/npx skills add https://github.com/freshworks-developers/fw-dev-tools --skill fw-setup/fw-setup-install/fw-setup-upgrade/fdk-install/fdk-upgradeSKILL.mdREADME.mdfdkfdkfw-setupskills/fw-setup/rules/smart-prerequisites-check.mdcnode --version 2>&1
fdk version 2>&1platform-versionengines.fdkengines.node| 已安装工具链 | 清单状态 | 操作 |
|---|---|---|
| FDK 9.x / Node 18 | Platform 2.x清单 | 停止 → 执行 |
| FDK 10.x / Node 24 | Platform 2.x清单 | 停止 → 执行 |
| FDK 10.x / Node 24 | Platform 3.0 + 引擎匹配 | ✅ 继续执行任务 |
| FDK 10.x / Node 24 | Platform 3.0 + 引擎不匹配 | 自动更新引擎、清理依赖,继续执行 |
| FDK 9.x / Node 18 | Platform 3.0清单 | 停止 → 执行 |
| 任意版本 | 无manifest.json | 仅检查工具链(新应用场景) |
fdk validaterm -rf node_modules coverage .fdk && npm installsmart-prerequisites-check.mdcfw-setupskills/fw-setup//fw-setup-install/fw-setup-upgrade/fw-setup-use/fw-setup-statusfdk validatefdk runfdk packfw-setupfw-setupfw-setupskills/fw-setup/npx skills add https://github.com/freshworks-developers/fw-dev-tools --skill fw-setupSKILL.mdREADME.md/fw-setup-install/fw-setup-upgrade/fdk-install/fdk-upgradefdkfdkfdkfdk versionfdk validatefdk packfdk runfdkfw-setup/fw-setup-install/fw-setup-status/fw-setup-installfw-setupSKILL.mdcommands/fdk versionfdk validatefdk packfdk runfdkfw-setup/fw-setup-install/fw-setup-status/fw-setup-installfw-setupSKILL.mdcommands/fdk validatefdk validatefdk validate/fdk-fix/fdk-review/fdk-refactor/fdk-migrate/fdk-migratenode --versionfdk versionmanifest.jsonplatform-versionengines.nodeengines.fdk| Condition | Action |
|---|---|
| STOP → offer |
Toolchain OK (Node 24.x + FDK 10.x) but | Do not use |
Toolchain OK, | Treat as incomplete migration: raise |
Toolchain OK, | Run |
fw-setup/fdk-migratefdk validate/fdk-migratefdk validatefw-setupfdk validate[WARN] App engines major version mismatchcoveragenode_modulesenginesenginesenginesnode --versionfdk versionnode_modules9.8.218.20.8fw-setup/fdk-migratefdk validatefdk validateasyncawaitfunctionasyncargs_argsexports = { ... }SetMaprenderDatarules/async-patterns.mdcconfig/requests.jsonmodules.common.requestsmanifest.jsonintegrationsoauth_config.json<%= access_token %>"options": { "oauth": "..." }Bearer <%= iparam.user_token %>app/styles/images/icon.svghost/README.mdfdk validateengines"fdk": "10.0.1""node": "24.11.0"enginesappmanifest.json"app""tracking_id""start_time"Ztracking_id[a-z0-9]{20}''.join(random.choice('abcdefghijklmnopqrstuvwxyz0123456789') for _ in range(20))start_timedatetime.utcnow().isoformat(timespec='milliseconds') + 'Z'2026-04-23T10:30:00.123Zmanifest.jsonengines"fdk": "10.0.1""node": "24.11.0"fdk validate10.0.124.11.0fdk validateenginesmanifest.jsonengines"node": "18.20.8""fdk": "9.8.2"fdk validate10.0.124.11.0enginesenginesplatform-versionfw-setup/fdk-migrateengines<reason>fdk validate10.0.124.11.0WARNING: DEPRECATED TOOLCHAIN — Manifest engines were set to FDK 9.8.2 + Node 18.20.8 as LAST RESORT after six validate iterations / CLI could not run on FDK 10.0.1 + Node 24.11.0.
Reason: <one-line summary>
- FDK 9.x + Node 18.x is DEPRECATED. Restore FDK 10.0.1 + Node 24.x for publishing.references/skill-advanced-topics.mdreferences/api-integration-examples.mdchangesmodel_changesreferences/events/onTicketUpdate-payload-contract.mdreferences/test-payloads/server/test_data/references/playbooks/README.mdReadGrepGlobRead/fdk-migratefdk validate/fdk-fix/fdk-review/fdk-refactor/fdk-migratenode --versionfdk versionmanifest.jsonplatform-versionengines.nodeengines.fdk| 条件 | 操作 |
|---|---|
| 停止 → 推荐使用** |
工具链正常(Node 24.x + FDK 10.x)但** | 不要将** |
工具链正常、 | 视为未完成迁移:升级 |
工具链正常、 | 执行** |
fw-setup/fdk-migratefdk validate/fdk-migratefdk validatefw-setupfdk validate[WARN] App engines major version mismatchcoveragenode_modulesenginesenginesnode --versionfdk versionenginesnode_modules9.8.218.20.8fw-setup/fdk-migratefdk validatefdk validateawaitasyncasyncfunctionargs_argsexports = { ... }SetMaprules/async-patterns.mdcrenderDataconfig/requests.jsonmanifest.jsonmodules.common.requestsoauth_config.jsonintegrations<%= access_token %>"options": { "oauth": "..." }Bearer <%= iparam.user_token %>app/styles/images/icon.svghost/fdk validateenginesengines"fdk": "10.0.1""node": "24.11.0"appmanifest.json"app""tracking_id""start_time"Z[a-z0-9]{20}tracking_id''.join(random.choice('abcdefghijklmnopqrstuvwxyz0123456789') for _ in range(20))start_timedatetime.utcnow().isoformat(timespec='milliseconds') + 'Z'2026-04-23T10:30:00.123Zmanifest.jsonengines"fdk": "10.0.1""node": "24.11.0"fdk validate10.0.124.11.0fdk validateenginesmanifest.jsonengines"node": "18.20.8""fdk": "9.8.2"10.0.124.11.0fdk validateengines10.0.124.11.0enginesplatform-versionfw-setup/fdk-migrateengines<reason>fdk validate10.0.124.11.0警告:已弃用工具链 — 经过6次验证迭代/CLI无法在FDK 10.0.1 + Node 24.11.0下运行,作为最后紧急方案,已将清单引擎设置为FDK 9.8.2 + Node 18.20.8。
原因:<一行摘要>
- FDK 9.x + Node 18.x已被弃用。发布应用时请恢复为FDK 10.0.1 + Node 24.x版本。references/skill-advanced-topics.mdreferences/api-integration-examples.mdchangesmodel_changesreferences/events/onTicketUpdate-payload-contract.mdreferences/test-payloads/server/test_data/references/playbooks/README.mdGrepGlobfdk validate"platform-version": "2.3""2.2""2.1""3.0""product": { "freshdesk": {} }"modules": {}"whitelisted-domains"$request.post().get().put().delete()$request.invokeTemplate()integrations{ "integrations": { ... } }"engines"fdk9node18fdk validate/<%= context.* %><%= iparam.* %><%= access_token %>{{}}rules/freshworks-platform3.mdcrules/validation-workflow.mdcapp/styles/images/icon.svgapp/styles/images/icon.svg<svg xmlns="http://www.w3.org/2000/svg" width="64" height="64" viewBox="0 0 64 64">
<rect width="64" height="64" rx="8" fill="#4A90D9"/>
<text x="32" y="40" font-family="Arial, sans-serif" font-size="24" font-weight="bold" fill="white" text-anchor="middle">App</text>
</svg>{{variable}}<%= context.variable %><%= iparam.name %><%= access_token %>config/requests.jsonmanifest.jsonmodules.common.requestsconfig/requests.json: manifest.json:
{ "modules": {
"createTask": {...}, → "common": {
"addComment": {...} → "requests": {
} "createTask": {},
"addComment": {}
}
}
}asyncawaitasync function(args)awaitfunction(args)asyncasync// [INVALID] async without await → lint error
exports = { onAppInstallHandler: async function(args) { console.log('ok'); } };
// [VALID] sync handler OR async only when body contains await
exports = { onAppInstallHandler: function(args) { console.log(args.iparams.domain); } };_argsfdk validate// [INVALID] unused args (and _args) → remove parameter entirely
onAppInstallHandler: function(args) { console.log('Installed'); }
// [VALID]
onAppInstallHandler: function() { console.log('Installed'); }
onAppInstallHandler: function(args) { console.log(args.iparams.domain); }fdk validate// [INVALID] WRONG - complexity 12 (each || and === adds +1)
function matchesPriority(ticket, filter) {
const p = (ticket.priority || ticket.urgency || 0).toString();
if (filter.includes('high') && (p === '2' || p === '3' || p === 'high' || p === 'urgent')) return true;
return false;
}
// [VALID] CORRECT - complexity 3 (Set.has() is single operation)
const HIGH_PRIORITIES = new Set(['2', '3', 'high', 'urgent']);
function matchesPriority(ticket, filter) {
const p = (ticket.priority || ticket.urgency || 0).toString();
if (filter.includes('high') && HIGH_PRIORITIES.has(p)) return true;
return false;
}exportsrules/complexity-reduction.mdclocationurl: "index.html"app/index.htmllocationicon: "styles/images/icon.svg"app/styles/images/icon.svgfunctionseventsserver/server.jsfdk validate"platform-version": "2.3""2.2""2.1""3.0""product": { "freshdesk": {} }"modules": {}"whitelisted-domains"$request.post().get().put().delete()$request.invokeTemplate()integrations{ "integrations": { ... } }fdk9node18"engines"fdk validate/<%= context.* %><%= iparam.* %><%= access_token %>{{}}rules/freshworks-platform3.mdcrules/validation-workflow.mdcapp/styles/images/icon.svgapp/styles/images/icon.svg<svg xmlns="http://www.w3.org/2000/svg" width="64" height="64" viewBox="0 0 64 64">
<rect width="64" height="64" rx="8" fill="#4A90D9"/>
<text x="32" y="40" font-family="Arial, sans-serif" font-size="24" font-weight="bold" fill="white" text-anchor="middle">App</text>
</svg>{{variable}}<%= context.variable %><%= iparam.name %><%= access_token %>config/requests.jsonmanifest.jsonmodules.common.requestsconfig/requests.json: manifest.json:
{ "modules": {
"createTask": {...}, → "common": {
"addComment": {...} → "requests": {
} "createTask": {},
"addComment": {}
}
}
}awaitasyncasync function(args)awaitasyncfunction(args)async// [无效] 无await的async → 代码检查错误
exports = { onAppInstallHandler: async function(args) { console.log('ok'); } };
// [有效] 同步处理程序或仅在函数体包含await时使用async
exports = { onAppInstallHandler: function(args) { console.log(args.iparams.domain); } };_argsfdk validate// [无效] 未使用的args(和_args)→ 完全移除参数
onAppInstallHandler: function(args) { console.log('Installed'); }
// [有效]
onAppInstallHandler: function() { console.log('Installed'); }
onAppInstallHandler: function(args) { console.log(args.iparams.domain); }fdk validate// [无效] 错误 - 复杂度12(每个||和===都会增加+1)
function matchesPriority(ticket, filter) {
const p = (ticket.priority || ticket.urgency || 0).toString();
if (filter.includes('high') && (p === '2' || p === '3' || p === 'high' || p === 'urgent')) return true;
return false;
}
// [有效] 正确 - 复杂度3(Set.has()是单个操作)
const HIGH_PRIORITIES = new Set(['2', '3', 'high', 'urgent']);
function matchesPriority(ticket, filter) {
const p = (ticket.priority || ticket.urgency || 0).toString();
if (filter.includes('high') && HIGH_PRIORITIES.has(p)) return true;
return false;
}exportsrules/complexity-reduction.mdclocationurl: "index.html"app/index.htmllocationicon: "styles/images/icon.svg"app/styles/images/icon.svgfunctionseventsserver/server.jsrules/security.mdcrules/complexity-reduction.mdcrules/security.mdcrules/complexity-reduction.mdc| Severity | Rule | Forbidden Pattern |
|---|---|---|
| [CRITICAL] CRITICAL | No command injection | |
| [CRITICAL] CRITICAL | No code execution | |
| [HIGH] HIGH | No logging secrets | |
| [MEDIUM] MEDIUM | No XSS | |
| [MEDIUM] MEDIUM | No secrets in notes | Passwords/tokens in ticket notes |
| 严重程度 | 规则 | 禁止模式 |
|---|---|---|
| [关键] CRITICAL | 禁止命令注入 | |
| [关键] CRITICAL | 禁止代码执行 | |
| [高] HIGH | 禁止记录敏感信息 | |
| [中] MEDIUM | 禁止XSS | 未 sanitize 的 |
| [中] MEDIUM | 禁止在备注中存储敏感信息 | 工单备注中包含密码/令牌 |
args.iparamsargstextContentinnerHTMLrules/security.mdcargs.iparamsargstextContentinnerHTMLrules/security.mdc{
"platform-version": "3.0",
"app": {
"tracking_id": "<20-char-lowercase-alphanumeric>",
"start_time": "<UTC-ISO8601-milliseconds-Z>"
},
"modules": {
"common": {
"requests": { "apiName": {} },
"functions": { "functionName": {} }
},
"support_ticket": {
"location": {
"ticket_sidebar": {
"url": "index.html",
"icon": "styles/images/icon.svg"
}
}
}
},
"engines": {
"node": "24.11.0",
"fdk": "10.0.1"
}
}name"name": "My App"namemust NOT have additional properties 'name' in manifest.json"functions": {}"requests": {}"events": {}"functions""requests"{
"platform-version": "3.0",
"app": {
"tracking_id": "<20-char-lowercase-alphanumeric>",
"start_time": "<UTC-ISO8601-milliseconds-Z>"
},
"modules": {
"common": {
"requests": { "apiName": {} },
"functions": { "functionName": {} }
},
"support_ticket": {
"location": {
"ticket_sidebar": {
"url": "index.html",
"icon": "styles/images/icon.svg"
}
}
}
},
"engines": {
"node": "24.11.0",
"fdk": "10.0.1"
}
}name"name": "My App"namemust NOT have additional properties 'name' in manifest.json"functions": {}"requests": {}"events": {}"functions""requests"platform-version3.0productwhitelisted-domains$request.post|get|put|deleteintegrationsexportsasyncawaitreferences/skill-advanced-topics.mdrules/freshworks-platform3.mdcplatform-version3.0productwhitelisted-domains$request.post|get|put|deleteintegrationsexportsawaitasyncreferences/skill-advanced-topics.mdrules/freshworks-platform3.mdcfdk validateundefinedfdk validateundefined
---
---ticketloggedInUserticketloggedInUserclient.data.get("ticket")client.data.get("loggedInUser")ticketloggedInUserticketloggedInUserclient.data.get("ticket")client.data.get("loggedInUser")| Prefer Hybrid / Frontend | Prefer Serverless only |
|---|---|
| Any UI, placement, dashboard, sync status, resync, config beyond iparams, user says "sync" (unless they insist serverless) | Pure automation, no monitoring, webhook fire-and-forget, user says "no UI" / "background only", notification-only |
rules/confusion.mdcUI? → yes → backend/events/API? → yes = Hybrid, no = Frontend-only
UI? → no → backend/events? → yes = Serverless, no = invalidrequests.jsonoauth-skeletonimplement_appget_implementation_planidea_to_appfix_app_errorsfw-app-devget_developer_docsfdk validate| Template folder | When | Main artifacts |
|---|---|---|
| UI only | |
| No UI, events/automation | |
| UI + SMI + external API | |
| UI + OAuth service | above + |
references/playbooks/README.mdfdkfw-setupskills/fw-setup/rules/smart-prerequisites-check.mdcnode --version 2>&1
fdk version 2>&1platform-versionengines.fdkengines.node| 已安装工具链 | 清单状态 | 操作 |
|---|---|---|
| FDK 9.x / Node 18 | Platform 2.x清单 | 停止 → 执行 |
| FDK 10.x / Node 24 | Platform 2.x清单 | 停止 → 执行 |
| FDK 10.x / Node 24 | Platform 3.0 + 引擎匹配 | ✅ 继续执行任务 |
| FDK 10.x / Node 24 | Platform 3.0 + 引擎不匹配 | 自动更新引擎、清理依赖,继续执行 |
| FDK 9.x / Node 18 | Platform 3.0清单 | 停止 → 执行 |
| 任意版本 | 无manifest.json | 仅检查工具链(新应用场景) |
fdk validaterm -rf node_modules coverage .fdk && npm installsmart-prerequisites-check.mdcfw-setupskills/fw-setup//fw-setup-install/fw-setup-upgrade/fw-setup-use/fw-setup-statusfdk validatefdk runfdk packfw-setupfw-setupfw-setupskills/fw-setup/npx skills add https://github.com/freshworks-developers/fw-dev-tools --skill fw-setupSKILL.mdREADME.md/fw-setup-install/fw-setup-upgrade/fdk-install/fdk-upgradefdkfdkfdk validatefdk validate10.0.124.11.0fdk validate{{variable}}<%= context.variable %>icon.svgiparams.jsonREADME.md//fdk validateintegrationsoauth_iparamsfdk validate[VALID] App generated successfully in <app-directory>/
Validation: 0 platform errors, 0 lint errors
Next steps:
1. cd <app-directory>
2. fdk run
3. Test in product with ?dev=true
4. When ready to publish: use the publish skill"name"asyncawait_argsfdk validatefdk validaterules/validation-workflow.mdcreferences/skill-advanced-topics.mdreferences/architecture/oauth-configuration-latest.mdreferences/api/oauth-docs.mdREADME.md # MANDATORY - create FIRST
app/
├── index.html # MUST include Crayons CDN
├── scripts/app.js # Use IIFE pattern for async
└── styles/
├── style.css
└── images/
└── icon.svg # REQUIRED - FDK validation fails without it
config/
└── iparams.json # REQUIRED - even if empty {}server/
└── server.js # Use $request.invokeTemplate()
config/
└── iparams.json # REQUIRED - even if empty {}app/ + server/ + config/requests.json + config/iparams.jsonapp/ + server/ + config/oauth_config.json + config/requests.json + config/iparams.jsonfdk versionfdk validatefdk packfdk runfdkfw-setup/fw-setup-install/fw-setup-status/fw-setup-installfw-setupSKILL.mdcommands/fdk validatefdk validatefdk validate10.0.124.11.0fdk validate{{variable}}<%= context.variable %>icon.svgiparams.jsonREADME.md//fdk validateintegrationsoauth_iparamsfdk validate[VALID] App generated successfully in <app-directory>/
Validation: 0 platform errors, 0 lint errors
Next steps:
1. cd <app-directory>
2. fdk run
3. Test in product with ?dev=true
4. When ready to publish: use the publish skillfdk validatefdk validate/fdk-migratefdk validate/fdk-fix/fdk-review/fdk-refactor/fdk-migratenode --versionfdk versionmanifest.jsonplatform-versionengines.nodeengines.fdk| 条件 | 操作 |
|---|---|
| 停止 → 推荐使用** |
工具链正常(Node 24.x + FDK 10.x)但** | 不要将** |
工具链正常、 | 视为未完成迁移:升级 |
工具链正常、 | 执行** |
fw-setup/fdk-migratefdk validate/fdk-migratefdk validatefw-setupfdk validate[WARN] App engines major version mismatchcoveragenode_modulesenginesenginesnode --versionfdk versionenginesnode_modules9.8.218.20.8fw-setup/fdk-migratefdk validatefdk validateawaitasyncasyncfunctionargs_argsexports = { ... }SetMaprules/async-patterns.mdcrenderDataconfig/requests.jsonmanifest.jsonmodules.common.requestsoauth_config.jsonintegrations<%= access_token %>"options": { "oauth": "..." }Bearer <%= iparam.user_token %>app/styles/images/icon.svghost/fdk validateenginesengines"fdk": "10.0.1""node": "24.11.0"appmanifest.json"app""tracking_id""start_time"Z[a-z0-9]{20}tracking_id''.join(random.choice('abcdefghijklmnopqrstuvwxyz0123456789') for _ in range(20))start_timedatetime.utcnow().isoformat(timespec='milliseconds') + 'Z'2026-04-23T10:30:00.123Zmanifest.jsonengines"fdk": "10.0.1""node": "24.11.0"fdk validate10.0.124.11.0fdk validateenginesmanifest.jsonengines"node": "18.20.8""fdk": "9.8.2"10.0.124.11.0fdk validateengines10.0.124.11.0enginesplatform-versionfw-setup/fdk-migrateengines<reason>fdk validate10.0.124.11.0警告:已弃用工具链 — 经过6次验证迭代/CLI无法在FDK 10.0.1 + Node 24.11.0下运行,作为最后紧急方案,已将清单引擎设置为FDK 9.8.2 + Node 18.20.8。
原因:<一行摘要>
- FDK 9.x + Node 18.x已被弃用。发布应用时请恢复为FDK 10.0.1 + Node 24.x版本。references/skill-advanced-topics.mdreferences/api-integration-examples.mdchangesmodel_changesreferences/events/onTicketUpdate-payload-contract.mdreferences/test-payloads/server/test_data/references/playbooks/README.mdGrepGlobreferences/tests/refusal.jsonreferences/tests/golden.jsonfdk validate"platform-version": "2.3""2.2""2.1""3.0""product": { "freshdesk": {} }"modules": {}"whitelisted-domains"$request.post().get().put().delete()$request.invokeTemplate()integrations{ "integrations": { ... } }fdk9node18"engines"fdk validate/<%= context.* %><%= iparam.* %><%= access_token %>{{}}rules/freshworks-platform3.mdcrules/validation-workflow.mdcapp/styles/images/icon.svgapp/styles/images/icon.svg<svg xmlns="http://www.w3.org/2000/svg" width="64" height="64" viewBox="0 0 64 64">
<rect width="64" height="64" rx="8" fill="#4A90D9"/>
<text x="32" y="40" font-family="Arial, sans-serif" font-size="24" font-weight="bold" fill="white" text-anchor="middle">App</text>
</svg>{{variable}}<%= context.variable %><%= iparam.name %><%= access_token %>config/requests.jsonmanifest.jsonmodules.common.requestsconfig/requests.json: manifest.json:
{ "modules": {
"createTask": {...}, → "common": {
"addComment": {...} → "requests": {
} "createTask": {},
"addComment": {}
}
}
}awaitasyncasync function(args)awaitasyncfunction(args)async// [无效] 无await的async → 代码检查错误
exports = { onAppInstallHandler: async function(args) { console.log('ok'); } };
// [有效] 同步处理程序或仅在函数体包含await时使用async
exports = { onAppInstallHandler: function(args) { console.log(args.iparams.domain); } };_argsfdk validate// [无效] 未使用的args(和_args)→ 完全移除参数
onAppInstallHandler: function(args) { console.log('Installed'); }
// [有效]
onAppInstallHandler: function() { console.log('Installed'); }
onAppInstallHandler: function(args) { console.log(args.iparams.domain); }fdk validate// [无效] 错误 - 复杂度12(每个||和===都会增加+1)
function matchesPriority(ticket, filter) {
const p = (ticket.priority || ticket.urgency || 0).toString();
if (filter.includes('high') && (p === '2' || p === '3' || p === 'high' || p === 'urgent')) return true;
return false;
}
// [有效] 正确 - 复杂度3(Set.has()是单个操作)
const HIGH_PRIORITIES = new Set(['2', '3', 'high', 'urgent']);
function matchesPriority(ticket, filter) {
const p = (ticket.priority || ticket.urgency || 0).toString();
if (filter.includes('high') && HIGH_PRIORITIES.has(p)) return true;
return false;
}exportsrules/complexity-reduction.mdclocationurl: "index.html"app/index.htmllocationicon: "styles/images/icon.svg"app/styles/images/icon.svgfunctionseventsserver/server.jsreferences/references/skill-advanced-topics.md<script async type="module" src="https://cdn.jsdelivr.net/npm/@freshworks/crayons@v4/dist/crayons/crayons.esm.js"></script>
<script async nomodule src="https://cdn.jsdelivr.net/npm/@freshworks/crayons@v4/dist/crayons/crayons.js"></script>rules/security.mdcrules/complexity-reduction.mdc| Check | Requirement |
|---|---|
| Icon | |
| Crayons | All frontend HTML includes CDN (above) |
| Engines | Default |
| Product module | At least one product module (may be |
| Iparams | Exactly one of: |
| 严重程度 | 规则 | 禁止模式 |
|---|---|---|
| [关键] CRITICAL | 禁止命令注入 | |
| [关键] CRITICAL | 禁止代码执行 | |
| [高] HIGH | 禁止记录敏感信息 | |
| [中] MEDIUM | 禁止XSS | 未 sanitize 的 |
| [中] MEDIUM | 禁止在备注中存储敏感信息 | 工单备注中包含密码/令牌 |
| Check | Requirement |
|---|---|
| Version / shape | |
| Requests / functions | Every template and SMI key declared under |
| Locations | Product locations in product module, not |
| OAuth | |
| Schedules | No scheduled events in manifest — use |
| Lifecycle | Non-empty iparams → |
args.iparamsargstextContentinnerHTMLrules/security.mdc| Check | Requirement |
|---|---|
| Params / async | No unused params; |
| Requests / exports | |
| Control flow | Complexity ≤ 7; no unreachable code |
| Errors | try/catch around async; SMI/events use |
| Comments | Brief on SMI; explain non-obvious logic only |
{
"platform-version": "3.0",
"app": {
"tracking_id": "<20-char-lowercase-alphanumeric>",
"start_time": "<UTC-ISO8601-milliseconds-Z>"
},
"modules": {
"common": {
"requests": { "apiName": {} },
"functions": { "functionName": {} }
},
"support_ticket": {
"location": {
"ticket_sidebar": {
"url": "index.html",
"icon": "styles/images/icon.svg"
}
}
}
},
"engines": {
"node": "24.11.0",
"fdk": "10.0.1"
}
}name"name": "My App"namemust NOT have additional properties 'name' in manifest.json"functions": {}"requests": {}"events": {}"functions""requests"rules/security.mdc| Check | Requirement |
|---|---|
| Input | SMI args validated; allowlists for enumerated ops |
| Injection | No |
| Logging | No |
| XSS / secrets | |
platform-version3.0productwhitelisted-domains$request.post|get|put|deleteintegrationsexportsawaitasyncreferences/skill-advanced-topics.mdrules/freshworks-platform3.mdc| Use | Not |
|---|---|
| Plain |
| Docs | |
fdk validateundefinedmy-app/zapier-sync-app/undefined
---
**Extended pre-generation numbered checklist, duplicate error-prevention lists, autofix iteration detail, and JSON merge examples:** `references/skill-advanced-topics.md`. **Operational workflow:** `rules/validation-workflow.mdc`. **Error catalog:** `references/errors/error-catalog.md`.| Gate | Checks |
|---|---|
| 1 – Files | |
| 2 – Manifest ↔ disk | Every |
| 3 – Manifest JSON | |
| 4 – OAuth (if used) | |
| 5 – Code quality | Complexity ≤ 7; async only with |
| 6 – Validate | |
fdk validate[VALID] App generated successfully in <app-directory>/
Validation: [0 platform errors, 0 lint errors]
Next steps:
1. cd <app-directory>
2. fdk run
3. Test in Freshworks product with ?dev=true
4. When ready to publish: use the publish skill// Check if MCP tools are available
try {
CallMcpTool("fw-dev-mcp", "list_custom_apps", {});
// Success: MCP already configured, skip prompt
} catch {
// MCP not configured: offer setup
// Full implementation: skills/fw-publish/subagents/mcp-config-prompt.md
Read and follow: skills/fw-publish/subagents/mcp-config-prompt.md
}═══════════════════════════════════════════════════════════
Optional: Configure Marketplace Publishing
Would you like to set up publishing tools now?
This connects your IDE to the Freshworks Marketplace API.
You can skip this and configure later.
Configure MCP now? (y/N)
═══════════════════════════════════════════════════════════skills/fw-publish/subagents/mcp-config-prompt.md/fw-setup-install
---| Always create | Only if user asks |
|---|---|
| |
| |
README.mdticketloggedInUserticketloggedInUserclient.data.get("ticket")client.data.get("loggedInUser")README.mdreferences/tests/refusal.jsonreferences/tests/golden.jsonreferences/skill-advanced-topics.mdrules/platform3-modules-locations.mdcreferences/skill-advanced-topics.md| 优先选择混合/前端 | 优先选择仅Serverless |
|---|---|
| 任何UI、放置位置、仪表盘、同步状态、重新同步、iparams之外的配置、用户提及“同步”(除非明确要求仅Serverless) | 纯自动化、无监控、webhook即发即弃、用户提及“无UI”/“仅后台运行”、仅通知场景 |
rules/confusion.mdc需要UI? → 是 → 需要后端/事件/API? → 是 = 混合类型,否 = 仅前端
需要UI? → 否 → 需要后端/事件? → 是 = Serverless,否 = 无效requests.jsonoauth-skeletonconsole.logserver/server.jsrules/freshworks-platform3.mdc| 模板目录 | 适用场景 | 主要产物 |
|---|---|---|
| 仅UI场景 | |
| 无UI、事件/自动化场景 | |
| UI + SMI + 外部API场景 | |
| UI + OAuth服务场景 | 上述文件 + |
references/playbooks/README.mdreferences/events/event-reference.mdonAppInstallonAppUninstallevents$schedule.create()onTicketUpdatereferences/events/onTicketUpdate-payload-contract.mdreferences/test-payloads/server/test_data/support_ticket/onTicketUpdate.json.../service_ticket/onTicketUpdate.jsonreferences/architecture/request-templates-latest.mdoauth-configuration-latest.mdreferences/api/request-method-docs.md/<%= %>options.oauthreferences/api-integration-examples.mdreferences/runtime/jobs-docs.mdmodules.common.jobsrenderDatafdk validate10.0.124.11.0fdk validatefdk validate{{variable}}<%= context.variable %>icon.svgiparams.jsonREADME.md//fdk validateintegrationsoauth_iparamsfdk validate[VALID] 应用已成功生成在<app-directory>/
验证结果:0平台错误,0代码检查错误
下一步:
1. cd <app-directory>
2. fdk run
3. 在产品中使用?dev=true进行测试
4. 准备发布时:使用发布技能"name"asyncawait_argsfdk validatefdk validaterules/validation-workflow.mdcreferences/skill-advanced-topics.mdreferences/architecture/oauth-configuration-latest.mdreferences/api/oauth-docs.mdREADME.md # 强制要求 - 首先创建
app/
├── index.html # 必须包含Crayons CDN
├── scripts/app.js # 前端初始化使用IIFE模式
└── styles/
├── style.css
└── images/
└── icon.svg # 必填 - 无此文件FDK验证失败
config/
└── iparams.json # 必填 - 即使为空{}server/
└── server.js # 使用$request.invokeTemplate()
config/
└── iparams.json # 必填 - 即使为空{}app/ + server/ + config/requests.json + config/iparams.jsonapp/ + server/ + config/oauth_config.json + config/requests.json + config/iparams.jsonreferences/| Task | Read in order |
|---|---|
| New hybrid + external HTTP | |
| New OAuth + external API | |
| Ticket serverless events / filters | |
| Multi-module / placement | |
| Lint / validate churn | |
rules/confusion.mdcfdk validate10.0.124.11.0fdk validatefdk validate{{variable}}<%= context.variable %>icon.svgiparams.jsonREADME.md//fdk validateintegrationsoauth_iparamsfdk validate[VALID] 应用已成功生成在<app-directory>/
验证结果:0平台错误,0代码检查错误
下一步:
1. cd <app-directory>
2. fdk run
3. 在产品中使用?dev=true进行测试
4. 准备发布时:使用发布技能fdk validatefdk validatereferences/skill-advanced-topics.mdreferences/references/tests/refusal.jsonreferences/tests/golden.jsonreferences/references/skill-advanced-topics.md<script async type="module" src="https://cdn.jsdelivr.net/npm/@freshworks/crayons@v4/dist/crayons/crayons.esm.js"></script>
<script async nomodule src="https://cdn.jsdelivr.net/npm/@freshworks/crayons@v4/dist/crayons/crayons.js"></script>| 检查项 | 要求 |
|---|---|
| 图标 | 前端应用必须存在 |
| Crayons | 所有前端HTML必须包含上述CDN |
| 引擎 | 默认使用** |
| 产品模块 | 至少包含一个产品模块(可为 |
| Iparams | 必须且仅包含以下一种: |
| 检查项 | 要求 |
|---|---|
| 版本/结构 | |
| 请求/函数 | 每个模板和SMI键必须在 |
| 位置 | 产品位置必须在产品模块中,而非 |
| OAuth | 使用OAuth时必须包含 |
| 定时任务 | 清单中不能包含定时事件 — 使用 |
| 生命周期 | 非空iparams → 必须包含 |
| 检查项 | 要求 |
|---|---|
| 参数/async | 无未使用参数;仅在包含 |
| 请求/exports | 仅使用 |
| 控制流 | 复杂度≤7;无不可达代码 |
| 错误处理 | 异步操作使用try/catch;SMI/事件按照 |
| 注释 | SMI注释简洁;仅对非显而易见的逻辑添加注释 |
rules/security.mdc| 检查项 | 要求 |
|---|---|
| 输入 | SMI参数已验证;枚举操作使用允许列表 |
| 注入 | 不对用户输入使用 |
| 日志 | 不记录 |
| XSS/敏感数据 | 使用 |
| 推荐使用 | 不推荐使用 |
|---|---|
| 原生 |
| 文档 | |
my-app/zapier-sync-app/undefined
---
**扩展预生成编号检查清单、重复错误预防列表、自动修复迭代细节和JSON合并示例:**`references/skill-advanced-topics.md`。**操作工作流:**`rules/validation-workflow.mdc`。**错误目录:**`references/errors/error-catalog.md`。| 准入条件 | 检查内容 |
|---|---|
| 1 – 文件 | |
| 2 – 清单 ↔ 磁盘一致性 | 每个 |
| 3 – 清单JSON | |
| 4 – OAuth(如果使用) | 每个 |
| 5 – 代码质量 | 复杂度≤7;仅在包含 |
| 6 – 验证 | |
fdk validate[VALID] 应用已成功生成在<app-directory>/
验证结果:[0平台错误,0代码检查错误]
下一步:
1. cd <app-directory>
2. fdk run
3. 在Freshworks产品中使用?dev=true进行测试
4. 准备发布时:使用发布技能// 检查MCP工具是否可用
try {
CallMcpTool("fw-dev-mcp", "list_custom_apps", {});
// 成功:MCP已配置,跳过提示
} catch {
// MCP未配置:提供设置选项
// 完整实现:skills/fw-publish/subagents/mcp-config-prompt.md
读取并遵循:skills/fw-publish/subagents/mcp-config-prompt.md
}═══════════════════════════════════════════════════════════
可选:配置应用市场发布工具
是否现在设置发布工具?
这会将你的IDE连接到Freshworks应用市场API。
你可以跳过此步骤,稍后再配置。
现在配置MCP?(y/N)
═══════════════════════════════════════════════════════════skills/fw-publish/subagents/mcp-config-prompt.md/fw-setup-install| 必须创建 | 仅在用户要求时创建 |
|---|---|
| |
根据模板创建 | |
README.mdREADME.mdreferences/tests/refusal.jsonreferences/tests/golden.jsonreferences/skill-advanced-topics.mdrules/platform3-modules-locations.mdcreferences/skill-advanced-topics.mdserver/server.jsconsole.logrules/freshworks-platform3.mdcreferences/events/event-reference.mdonAppInstallonAppUninstallevents$schedule.create()onTicketUpdatereferences/events/onTicketUpdate-payload-contract.mdreferences/test-payloads/server/test_data/support_ticket/onTicketUpdate.json.../service_ticket/onTicketUpdate.jsonreferences/architecture/request-templates-latest.mdoauth-configuration-latest.mdreferences/api/request-method-docs.md/<%= %>options.oauthreferences/api-integration-examples.mdreferences/runtime/jobs-docs.mdmodules.common.jobsrenderDatareferences/| 任务 | 读取顺序 |
|---|---|
| 新混合应用 + 外部HTTP | |
| 新OAuth应用 + 外部API | |
| 工单Serverless事件 / 过滤器 | |
| 多模块 / 位置配置 | |
| 代码检查 / 验证迭代 | |
rules/confusion.mdcreferences/skill-advanced-topics.mdreferences/