@tenonhq/dovetail-core 0.0.85
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -0
- package/dist/FileLogger.js +207 -0
- package/dist/FileUtils.js +387 -0
- package/dist/Logger.js +88 -0
- package/dist/MultiScopeWatcher.js +615 -0
- package/dist/PluginManager.js +125 -0
- package/dist/_defaultOptionsOLD.js +44 -0
- package/dist/allScopesCommands.js +418 -0
- package/dist/appUtils.js +929 -0
- package/dist/benchmark.js +104 -0
- package/dist/bootstrap.js +62 -0
- package/dist/claudeCommand.js +60 -0
- package/dist/clickupCommands.js +472 -0
- package/dist/clickupPushHelper.js +33 -0
- package/dist/commander.js +466 -0
- package/dist/commands.js +378 -0
- package/dist/config.js +697 -0
- package/dist/constants.js +15 -0
- package/dist/createRecordCommand.js +314 -0
- package/dist/dashboardCommand.js +38 -0
- package/dist/defaultOptions.js +14 -0
- package/dist/deleteRecordCommand.js +282 -0
- package/dist/flowDesigner/values.js +55 -0
- package/dist/genericUtils.js +189 -0
- package/dist/gitUtils.js +99 -0
- package/dist/index.js +35 -0
- package/dist/initSystem/corePlugin.js +344 -0
- package/dist/initSystem/discovery.js +107 -0
- package/dist/initSystem/orchestrator.js +408 -0
- package/dist/logMessages.js +82 -0
- package/dist/loginCommand.js +20 -0
- package/dist/migrateCommand.js +123 -0
- package/dist/projectFiles.js +32 -0
- package/dist/recentEdits.js +66 -0
- package/dist/schemaCommand.js +85 -0
- package/dist/snClient.js +519 -0
- package/dist/tests/benchmarkRefresh.test.js +265 -0
- package/dist/tests/clickupCommands.test.js +384 -0
- package/dist/tests/clickupPushHelper.test.js +124 -0
- package/dist/tests/configFallback.test.js +68 -0
- package/dist/tests/cred.test.js +59 -0
- package/dist/tests/discovery.test.js +67 -0
- package/dist/tests/ensureUpdateSetWarnings.test.js +218 -0
- package/dist/tests/errorLogLevels.test.js +273 -0
- package/dist/tests/example.test.js +6 -0
- package/dist/tests/fileContextSkipReason.test.js +116 -0
- package/dist/tests/globalDebounce.test.js +308 -0
- package/dist/tests/migrateCommand.test.js +113 -0
- package/dist/tests/multi-scope-watcher.test.js +558 -0
- package/dist/tests/orchestrator.test.js +23 -0
- package/dist/tests/pushFiles.test.js +248 -0
- package/dist/tests/rateLimitCoordination.test.js +271 -0
- package/dist/tests/resolveConfigReadOnly.test.js +67 -0
- package/dist/tests/retryOnHttpErr.test.js +154 -0
- package/dist/tests/scopeCaching.test.js +115 -0
- package/dist/tests/serializeUpdateSetConfig.test.js +325 -0
- package/dist/tests/snClient.fallback.test.js +120 -0
- package/dist/tests/syncManifestRefresh.test.js +287 -0
- package/dist/tests/syncManifestWhitelist.test.js +192 -0
- package/dist/tests/taskClear.test.js +170 -0
- package/dist/tests/taskStaleness.test.js +220 -0
- package/dist/tests/unwrapSNResponseError.test.js +145 -0
- package/dist/tests/v2Values.test.js +79 -0
- package/dist/tests/validateTaskId.test.js +304 -0
- package/dist/tests/verifyUpdateSetSwitch.test.js +277 -0
- package/dist/tests/writeEnvVar.test.js +119 -0
- package/dist/updateSetCommands.js +702 -0
- package/dist/wizard.js +40 -0
- package/package.json +69 -0
- package/skills/dove-configure-pipeline.md +158 -0
- package/skills/dove-create-plugin.md +174 -0
- package/skills/dove-create-record.md +135 -0
- package/skills/dove-debug-build.md +117 -0
- package/skills/dove-delete-record.md +104 -0
- package/skills/dove-manage-tables.md +174 -0
- package/skills/dove-manage-update-sets.md +88 -0
- package/skills/dove-setup-project.md +154 -0
- package/skills/dove-troubleshoot-sync.md +113 -0
package/dist/wizard.js
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.getLoginInfo = getLoginInfo;
|
|
7
|
+
exports.setupDotEnv = setupDotEnv;
|
|
8
|
+
const inquirer_1 = __importDefault(require("inquirer"));
|
|
9
|
+
const FileUtils_1 = require("./FileUtils");
|
|
10
|
+
async function getLoginInfo() {
|
|
11
|
+
return await inquirer_1.default.prompt([
|
|
12
|
+
{
|
|
13
|
+
type: "input",
|
|
14
|
+
name: "instance",
|
|
15
|
+
message: "What instance would you like to connect to?(ex. test123.service-now.com)",
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
type: "input",
|
|
19
|
+
name: "username",
|
|
20
|
+
message: "What is your username on that instance?",
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
type: "password",
|
|
24
|
+
name: "password",
|
|
25
|
+
message: "What is your password on that instance?",
|
|
26
|
+
},
|
|
27
|
+
]);
|
|
28
|
+
}
|
|
29
|
+
async function setupDotEnv(answers) {
|
|
30
|
+
process.env.SN_USER = answers.username;
|
|
31
|
+
process.env.SN_PASSWORD = answers.password;
|
|
32
|
+
process.env.SN_INSTANCE = answers.instance;
|
|
33
|
+
(0, FileUtils_1.writeEnvVars)({
|
|
34
|
+
vars: [
|
|
35
|
+
{ key: "SN_USER", value: answers.username },
|
|
36
|
+
{ key: "SN_PASSWORD", value: answers.password },
|
|
37
|
+
{ key: "SN_INSTANCE", value: answers.instance },
|
|
38
|
+
],
|
|
39
|
+
});
|
|
40
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@tenonhq/dovetail-core",
|
|
3
|
+
"version": "0.0.85",
|
|
4
|
+
"description": "Next-gen file syncer",
|
|
5
|
+
"license": "GPL-3.0",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"author": "Multiple",
|
|
8
|
+
"private": false,
|
|
9
|
+
"scripts": {
|
|
10
|
+
"copy:skills": "mkdir -p skills && cp ../../skills/*.md ./skills/",
|
|
11
|
+
"prepack": "npm run copy:skills && tsc && npm run validate-dist",
|
|
12
|
+
"validate-dist": "node -e \"var fs=require('fs');if(!fs.existsSync('./dist/index.js')){console.error('FATAL: dist/index.js missing after build');process.exit(1)}\"",
|
|
13
|
+
"test": "jest --ci --reporters=jest-junit --reporters=default --coverage --coverageReporters=cobertura --coverageReporters=html",
|
|
14
|
+
"version:bump": "node ./../../Scripts/bump-version.js ./package.json",
|
|
15
|
+
"postpublish": "npm run version:bump"
|
|
16
|
+
},
|
|
17
|
+
"repository": {
|
|
18
|
+
"type": "git",
|
|
19
|
+
"url": "https://github.com/tenonhq/dovetail.git"
|
|
20
|
+
},
|
|
21
|
+
"engines": {
|
|
22
|
+
"node": ">=20.0.0"
|
|
23
|
+
},
|
|
24
|
+
"devDependencies": {
|
|
25
|
+
"@tenonhq/dovetail-types": "^0.0.17",
|
|
26
|
+
"@types/dotenv": "^6.1.1",
|
|
27
|
+
"@types/inquirer": "^8.2.10",
|
|
28
|
+
"@types/jest": "^29.5.5",
|
|
29
|
+
"@types/lodash": "^4.14.199",
|
|
30
|
+
"@types/node": ">=20.8.4",
|
|
31
|
+
"@types/prettier": "^2.7.3",
|
|
32
|
+
"@types/progress": "^2.0.5",
|
|
33
|
+
"@types/tough-cookie": "^4.0.5",
|
|
34
|
+
"@types/yargs": "^17.0.28",
|
|
35
|
+
"jest": "^29.7.0",
|
|
36
|
+
"jest-junit": "^16.0.0",
|
|
37
|
+
"ts-jest": "^29.1.1",
|
|
38
|
+
"typescript": "^5.2.2"
|
|
39
|
+
},
|
|
40
|
+
"dependencies": {
|
|
41
|
+
"@tenonhq/dovetail-clickup": "^0.0.7",
|
|
42
|
+
"@tenonhq/dovetail-schema": "^0.0.5",
|
|
43
|
+
"axios": "^1.5.1",
|
|
44
|
+
"axios-cookiejar-support": "^4.0.7",
|
|
45
|
+
"axios-rate-limit": "^1.3.0",
|
|
46
|
+
"chalk": "^4.1.2",
|
|
47
|
+
"chokidar": "^3.5.3",
|
|
48
|
+
"dotenv": "^16.3.1",
|
|
49
|
+
"inquirer": "^8.2.6",
|
|
50
|
+
"lodash": "^4.17.21",
|
|
51
|
+
"prettier": "3.0.3",
|
|
52
|
+
"progress": "^2.0.3",
|
|
53
|
+
"tough-cookie": "^4.1.3",
|
|
54
|
+
"winston": "^3.11.0",
|
|
55
|
+
"yargs": "^17.7.2"
|
|
56
|
+
},
|
|
57
|
+
"bin": {
|
|
58
|
+
"dove": "./dist/index.js",
|
|
59
|
+
"sinc": "./dist/index.js"
|
|
60
|
+
},
|
|
61
|
+
"files": [
|
|
62
|
+
"dist/**/*",
|
|
63
|
+
"skills/**/*",
|
|
64
|
+
"README.md"
|
|
65
|
+
],
|
|
66
|
+
"publishConfig": {
|
|
67
|
+
"access": "public"
|
|
68
|
+
}
|
|
69
|
+
}
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
# Configure Dovetail Build Pipeline
|
|
2
|
+
|
|
3
|
+
## Task
|
|
4
|
+
$ARGUMENTS
|
|
5
|
+
|
|
6
|
+
## Instructions for Claude
|
|
7
|
+
|
|
8
|
+
### Directory Context
|
|
9
|
+
|
|
10
|
+
Dovetail commands can be run from two locations:
|
|
11
|
+
- **From `ServiceNow/` directory:** `npx sinc <command>`
|
|
12
|
+
- **From Craftsman root:** `npm run sinc:<command>` (proxy scripts)
|
|
13
|
+
|
|
14
|
+
Available root scripts: `sinc:init`, `sinc:start`, `sinc:dev`, `sinc:build`, `sinc:deploy`, `sinc:push`, `sinc:refresh`, `sinc:status`
|
|
15
|
+
|
|
16
|
+
When running from Craftsman root, `dove.config.js` is at `ServiceNow/dove.config.js`. When running from `ServiceNow/`, it is at `./dove.config.js`. Use the path appropriate to the current working directory.
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
The user wants to configure or modify their `dove.config.js` plugin pipeline. Help them set up the `rules` array with the correct plugins, ordering, and options.
|
|
21
|
+
|
|
22
|
+
### Key Principles
|
|
23
|
+
|
|
24
|
+
1. **Rule matching is first-match-wins.** Place the most specific regex patterns first. If `.secret.ts` should have no plugins, that rule MUST come before the generic `.ts` rule.
|
|
25
|
+
2. **Plugin chain is sequential.** The output of one plugin feeds into the next. Order matters.
|
|
26
|
+
3. **Babel preset execution is REVERSED** (last preset runs first), but **Babel plugin execution is FORWARD** (first plugin runs first). This is standard Babel behavior but confusing in config.
|
|
27
|
+
|
|
28
|
+
### Step 1: Identify the user's file types and needs
|
|
29
|
+
|
|
30
|
+
Ask what file types they have if not specified:
|
|
31
|
+
- `.ts` files (server-side TypeScript)
|
|
32
|
+
- `.js` files (server-side JavaScript)
|
|
33
|
+
- `.client.js` or `.wp.js` files (client-side, need Webpack bundling)
|
|
34
|
+
- `.scss` files (SCSS stylesheets)
|
|
35
|
+
- Any files that should be excluded from processing
|
|
36
|
+
|
|
37
|
+
### Step 2: Build the rules array
|
|
38
|
+
|
|
39
|
+
For each file type, construct a rule using these templates:
|
|
40
|
+
|
|
41
|
+
**Server-side TypeScript (most common):**
|
|
42
|
+
```javascript
|
|
43
|
+
{
|
|
44
|
+
match: /\.ts$/,
|
|
45
|
+
plugins: [
|
|
46
|
+
{
|
|
47
|
+
name: "@tenonhq/dovetail-typescript-plugin",
|
|
48
|
+
options: { transpile: false }
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
name: "@tenonhq/dovetail-babel-plugin",
|
|
52
|
+
options: {
|
|
53
|
+
presets: [
|
|
54
|
+
"@tenonhq/dovetail-servicenow",
|
|
55
|
+
"@babel/env",
|
|
56
|
+
"@babel/typescript"
|
|
57
|
+
],
|
|
58
|
+
plugins: [
|
|
59
|
+
"@tenonhq/dovetail-remove-modules",
|
|
60
|
+
"@babel/proposal-class-properties",
|
|
61
|
+
"@babel/proposal-object-rest-spread"
|
|
62
|
+
]
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
]
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
**Server-side JavaScript:**
|
|
70
|
+
```javascript
|
|
71
|
+
{
|
|
72
|
+
match: /\.js$/,
|
|
73
|
+
plugins: [
|
|
74
|
+
{
|
|
75
|
+
name: "@tenonhq/dovetail-babel-plugin",
|
|
76
|
+
options: {
|
|
77
|
+
presets: [
|
|
78
|
+
"@tenonhq/dovetail-servicenow",
|
|
79
|
+
"@babel/env"
|
|
80
|
+
],
|
|
81
|
+
plugins: [
|
|
82
|
+
"@tenonhq/dovetail-remove-modules"
|
|
83
|
+
]
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
]
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
**Client-side Webpack bundle:**
|
|
91
|
+
```javascript
|
|
92
|
+
{
|
|
93
|
+
match: /\.wp\.js$/,
|
|
94
|
+
plugins: [
|
|
95
|
+
{
|
|
96
|
+
name: "@tenonhq/dovetail-webpack-plugin",
|
|
97
|
+
options: {
|
|
98
|
+
configGenerator: (context) => ({
|
|
99
|
+
mode: "production",
|
|
100
|
+
output: { library: context.name }
|
|
101
|
+
})
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
]
|
|
105
|
+
}
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
**SCSS:**
|
|
109
|
+
```javascript
|
|
110
|
+
{
|
|
111
|
+
match: /\.scss$/,
|
|
112
|
+
plugins: [
|
|
113
|
+
{ name: "@tenonhq/dovetail-sass-plugin", options: {} }
|
|
114
|
+
]
|
|
115
|
+
}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
**Skip processing:**
|
|
119
|
+
```javascript
|
|
120
|
+
{
|
|
121
|
+
match: /\.secret\.ts$/,
|
|
122
|
+
plugins: []
|
|
123
|
+
}
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### Step 3: Assemble the complete config
|
|
127
|
+
|
|
128
|
+
Write the full `dove.config.js` with rules ordered most-specific to least-specific. Include other fields: `sourceDirectory`, `buildDirectory`, `excludes`, `includes`, `tableOptions`, `refreshInterval`, `scopes`.
|
|
129
|
+
|
|
130
|
+
### Step 4: List npm install commands
|
|
131
|
+
|
|
132
|
+
Provide a single `npm i -D` command with all required packages.
|
|
133
|
+
|
|
134
|
+
### Available Plugins Reference
|
|
135
|
+
|
|
136
|
+
| Plugin | Purpose | npm Package |
|
|
137
|
+
|--------|---------|-------------|
|
|
138
|
+
| TypeScript | Type-check and/or transpile `.ts` | `@tenonhq/dovetail-typescript-plugin` |
|
|
139
|
+
| Babel | Run Babel transforms | `@tenonhq/dovetail-babel-plugin` |
|
|
140
|
+
| ESLint | Lint before sync (blocks on errors) | `@tenonhq/dovetail-eslint-plugin` |
|
|
141
|
+
| Prettier | Format output code | `@tenonhq/dovetail-prettier-plugin` |
|
|
142
|
+
| SASS | Compile SCSS to CSS | `@tenonhq/dovetail-sass-plugin` |
|
|
143
|
+
| Webpack | Bundle frontend JS | `@tenonhq/dovetail-webpack-plugin` |
|
|
144
|
+
|
|
145
|
+
### Babel Sub-Packages (used inside babel-plugin options)
|
|
146
|
+
|
|
147
|
+
| Package | Purpose | Config Key |
|
|
148
|
+
|---------|---------|------------|
|
|
149
|
+
| `@tenonhq/dovetail-babel-plugin-remove-modules` | Strip import/export for ServiceNow | `plugins: ["@tenonhq/dovetail-remove-modules"]` |
|
|
150
|
+
| `@tenonhq/dovetail-babel-preset-servicenow` | Sanitize for Rhino engine | `presets: ["@tenonhq/dovetail-servicenow"]` |
|
|
151
|
+
|
|
152
|
+
### Critical Warnings
|
|
153
|
+
|
|
154
|
+
- **Never use `useBuiltIns`** with `@babel/env` -- ServiceNow's Rhino engine locks base class prototypes, so polyfills will fail.
|
|
155
|
+
- **Always include `@tenonhq/dovetail-servicenow`** as the FIRST Babel preset listed (runs last) for server-side code -- it handles `__proto__` and reserved word issues.
|
|
156
|
+
- **Always include `@tenonhq/dovetail-remove-modules`** as a Babel plugin for server-side code -- ServiceNow does not support ES modules.
|
|
157
|
+
- If using TypeScript plugin for type-checking only (`transpile: false`), Babel must handle the actual transpilation.
|
|
158
|
+
- Webpack rules MUST come before generic `.js` rules in the rules array.
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
# Create a Custom Dovetail Plugin
|
|
2
|
+
|
|
3
|
+
## Task
|
|
4
|
+
$ARGUMENTS
|
|
5
|
+
|
|
6
|
+
## Instructions for Claude
|
|
7
|
+
|
|
8
|
+
### Directory Context
|
|
9
|
+
|
|
10
|
+
Dovetail commands can be run from two locations:
|
|
11
|
+
- **From `ServiceNow/` directory:** `npx sinc <command>`
|
|
12
|
+
- **From Craftsman root:** `npm run sinc:<command>` (proxy scripts)
|
|
13
|
+
|
|
14
|
+
Available root scripts: `sinc:init`, `sinc:start`, `sinc:dev`, `sinc:build`, `sinc:deploy`, `sinc:push`, `sinc:refresh`, `sinc:status`
|
|
15
|
+
|
|
16
|
+
Plugin files and `dove.config.js` live in the `ServiceNow/` directory. When referencing paths from the Craftsman root, prefix with `ServiceNow/`.
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
Help the user create a custom Dovetail build plugin. A plugin is a Node.js module that transforms file content during the build pipeline.
|
|
21
|
+
|
|
22
|
+
### Plugin Interface
|
|
23
|
+
|
|
24
|
+
A Dovetail plugin must export an object with a `run` function:
|
|
25
|
+
|
|
26
|
+
```typescript
|
|
27
|
+
interface Plugin {
|
|
28
|
+
run: (
|
|
29
|
+
context: FileContext,
|
|
30
|
+
content: string,
|
|
31
|
+
options: any
|
|
32
|
+
) => Promise<PluginResults>;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
interface FileContext {
|
|
36
|
+
filePath: string; // Absolute path to the source file
|
|
37
|
+
name: string; // Record display name
|
|
38
|
+
tableName: string; // ServiceNow table name
|
|
39
|
+
targetField: string; // Field name in ServiceNow
|
|
40
|
+
ext: string; // File extension
|
|
41
|
+
sys_id: string; // ServiceNow record sys_id
|
|
42
|
+
scope: string; // Application scope
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
interface PluginResults {
|
|
46
|
+
success: boolean; // If false, build is halted
|
|
47
|
+
output: string; // Transformed content (passed to next plugin)
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Minimal Plugin Template
|
|
52
|
+
|
|
53
|
+
```javascript
|
|
54
|
+
// my-dovetail-plugin/index.js
|
|
55
|
+
module.exports = {
|
|
56
|
+
run: async function(context, content, options) {
|
|
57
|
+
try {
|
|
58
|
+
let output = content;
|
|
59
|
+
|
|
60
|
+
// Example: Add a header comment
|
|
61
|
+
if (options.addHeader) {
|
|
62
|
+
output = "// Generated from " + context.name + "\n" + output;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return { success: true, output: output };
|
|
66
|
+
} catch (e) {
|
|
67
|
+
console.error("Plugin error: " + e.message);
|
|
68
|
+
return { success: false, output: "" };
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### Plugin Registration in dove.config.js
|
|
75
|
+
|
|
76
|
+
```javascript
|
|
77
|
+
rules: [
|
|
78
|
+
{
|
|
79
|
+
match: /\.ts$/,
|
|
80
|
+
plugins: [
|
|
81
|
+
{
|
|
82
|
+
name: "my-dovetail-plugin",
|
|
83
|
+
options: { addHeader: true }
|
|
84
|
+
}
|
|
85
|
+
]
|
|
86
|
+
}
|
|
87
|
+
]
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
**Important:** Dovetail resolves plugins from `node_modules/` using the plugin name as a path segment. For local plugins, you have three options:
|
|
91
|
+
|
|
92
|
+
1. **Use npm link:**
|
|
93
|
+
```bash
|
|
94
|
+
cd plugins/my-plugin && npm link
|
|
95
|
+
npm link my-dovetail-plugin
|
|
96
|
+
```
|
|
97
|
+
2. **Use npm workspaces** (recommended for monorepos)
|
|
98
|
+
3. **Publish to npm** as a scoped package (recommended for shared plugins)
|
|
99
|
+
|
|
100
|
+
### Using the FileContext
|
|
101
|
+
|
|
102
|
+
```javascript
|
|
103
|
+
run: async function(context, content, options) {
|
|
104
|
+
// Different behavior per table
|
|
105
|
+
if (context.tableName === "sys_script_include") {
|
|
106
|
+
// Server-side script include
|
|
107
|
+
} else if (context.tableName === "sp_widget") {
|
|
108
|
+
// Service Portal widget
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Different behavior per file extension
|
|
112
|
+
if (context.ext === ".ts") {
|
|
113
|
+
// TypeScript file
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
console.log("Processing: " + context.name + " (" + context.sys_id + ")");
|
|
117
|
+
|
|
118
|
+
return { success: true, output: content };
|
|
119
|
+
}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### Plugin Chain Behavior
|
|
123
|
+
|
|
124
|
+
Plugins run sequentially. Each plugin receives the OUTPUT of the previous plugin as its `content` parameter. If any plugin returns `{ success: false }`, the entire build for that file is halted.
|
|
125
|
+
|
|
126
|
+
```
|
|
127
|
+
Source File Content
|
|
128
|
+
|
|
|
129
|
+
v
|
|
130
|
+
Plugin 1 (e.g., TypeScript type-check) --> output
|
|
131
|
+
|
|
|
132
|
+
v
|
|
133
|
+
Plugin 2 (e.g., Babel transpile) --> output
|
|
134
|
+
|
|
|
135
|
+
v
|
|
136
|
+
Plugin 3 (e.g., Prettier format) --> output
|
|
137
|
+
|
|
|
138
|
+
v
|
|
139
|
+
Final content pushed to ServiceNow
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### Example: Minification Plugin
|
|
143
|
+
|
|
144
|
+
```javascript
|
|
145
|
+
// my-minify-plugin/index.js
|
|
146
|
+
var terser = require("terser");
|
|
147
|
+
|
|
148
|
+
module.exports = {
|
|
149
|
+
run: async function(context, content, options) {
|
|
150
|
+
try {
|
|
151
|
+
if (context.ext === ".css" || context.ext === ".scss") {
|
|
152
|
+
return { success: true, output: content };
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
var result = await terser.minify(content, {
|
|
156
|
+
compress: options.compress !== false,
|
|
157
|
+
mangle: options.mangle !== false
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
return { success: true, output: result.code };
|
|
161
|
+
} catch (e) {
|
|
162
|
+
console.error("Minification failed for " + context.name + ": " + e.message);
|
|
163
|
+
return { success: false, output: "" };
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
};
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### Error Handling
|
|
170
|
+
|
|
171
|
+
- Return `{ success: false, output: "" }` to stop the build for that file
|
|
172
|
+
- Throw an exception for unexpected errors (caught by PluginManager)
|
|
173
|
+
- Log useful error messages -- they appear in the Dovetail console output
|
|
174
|
+
- Check `dovetail-debug-*.log` for detailed error traces
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
# Create ServiceNow Records
|
|
2
|
+
|
|
3
|
+
## Task
|
|
4
|
+
$ARGUMENTS
|
|
5
|
+
|
|
6
|
+
## Instructions for Claude
|
|
7
|
+
|
|
8
|
+
### Directory Context
|
|
9
|
+
|
|
10
|
+
Dovetail commands can be run from two locations:
|
|
11
|
+
- **From `ServiceNow/` directory:** `npx sinc <command>`
|
|
12
|
+
- **From Craftsman root:** `npm run sinc:<command>` (proxy scripts)
|
|
13
|
+
|
|
14
|
+
The `create` command requires running from the `ServiceNow/` directory directly, as it accepts flags and arguments that npm run scripts don't forward.
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
Help the user create new records on a ServiceNow instance using Dovetail's `create` command. After creation, the record is automatically pulled back and scaffolded locally.
|
|
19
|
+
|
|
20
|
+
### Command Syntax
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
npx dove create <table> [options]
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
### Options
|
|
27
|
+
|
|
28
|
+
| Flag | Alias | Type | Description |
|
|
29
|
+
|------|-------|------|-------------|
|
|
30
|
+
| `--name` | `-n` | string | Record name |
|
|
31
|
+
| `--scope` | `-s` | string | Target scope (e.g., x_cadso_core) |
|
|
32
|
+
| `--from` | `-f` | string | Path to JSON file with field values |
|
|
33
|
+
| `--field` | | array | Inline field values (key=value) |
|
|
34
|
+
| `--ci` | | boolean | Skip interactive prompts |
|
|
35
|
+
|
|
36
|
+
### Examples
|
|
37
|
+
|
|
38
|
+
#### Create a Script Include (interactive)
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
npx dove create sys_script_include
|
|
42
|
+
# Prompts for: name, scope
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
#### Create with flags
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
npx dove create sys_script_include --name "MyNewUtil" --scope x_cadso_core
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
#### Create with inline field values
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
npx dove create sys_script_include \
|
|
55
|
+
--name "MyNewUtil" \
|
|
56
|
+
--scope x_cadso_core \
|
|
57
|
+
--field active=true \
|
|
58
|
+
--field access=public
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
#### Create from JSON file
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
npx dove create sys_script_include --from new-script.json --scope x_cadso_core
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
**JSON file format (`new-script.json`):**
|
|
68
|
+
```json
|
|
69
|
+
{
|
|
70
|
+
"name": "MyNewUtil",
|
|
71
|
+
"active": "true",
|
|
72
|
+
"access": "public",
|
|
73
|
+
"script": "var MyNewUtil = Class.create();\nMyNewUtil.prototype = {\n initialize: function() {},\n type: 'MyNewUtil'\n};"
|
|
74
|
+
}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
#### Create a Business Rule
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
npx dove create sys_script --name "Validate Record" --scope x_cadso_automate
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
#### CI/Automation mode
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
npx dove create sys_script_include \
|
|
87
|
+
--name "AutoCreated" \
|
|
88
|
+
--scope x_cadso_core \
|
|
89
|
+
--from record.json \
|
|
90
|
+
--ci
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### What Happens After Create
|
|
94
|
+
|
|
95
|
+
1. **Record is created** on the ServiceNow instance via the `api/cadso/dovetail/createRecord` endpoint
|
|
96
|
+
2. **GlideRecord** uses `initialize()` and `newRecord()` to ensure all default values are set
|
|
97
|
+
3. **Manifest is refreshed** for the target scope
|
|
98
|
+
4. **Local files are scaffolded** — directory, field files (script.js, etc.), and metaData.json
|
|
99
|
+
5. **You can immediately begin editing** the local files and push changes
|
|
100
|
+
|
|
101
|
+
### Update Set Integration
|
|
102
|
+
|
|
103
|
+
If the target scope has an active update set configured (via `.dove-update-sets.json` or the dashboard), the new record is created within that update set.
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
# Set up update set first
|
|
107
|
+
npx dove createUpdateSet --name "FEAT-123" --scope x_cadso_core
|
|
108
|
+
|
|
109
|
+
# Create record — automatically goes into FEAT-123 update set
|
|
110
|
+
npx dove create sys_script_include --name "NewFeature" --scope x_cadso_core
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### Common Table Names
|
|
114
|
+
|
|
115
|
+
| Table | Creates |
|
|
116
|
+
|-------|---------|
|
|
117
|
+
| `sys_script_include` | Script Include (server-side utility class) |
|
|
118
|
+
| `sys_script` | Business Rule |
|
|
119
|
+
| `sys_ui_script` | UI Script (client-side) |
|
|
120
|
+
| `sys_ui_page` | UI Page |
|
|
121
|
+
| `sys_ux_client_script` | UX Client Script |
|
|
122
|
+
| `sys_processor` | Processor |
|
|
123
|
+
| `sys_ws_operation` | REST API Operation |
|
|
124
|
+
| `sys_rest_message_fn` | REST Message Function |
|
|
125
|
+
| `sys_ui_action` | UI Action |
|
|
126
|
+
| `sysevent_script_action` | Event Script Action |
|
|
127
|
+
|
|
128
|
+
### Troubleshooting
|
|
129
|
+
|
|
130
|
+
- **"Table name is required"** — Provide the table as the first argument: `npx dove create sys_script_include`
|
|
131
|
+
- **"Record name is required"** — Use `--name` flag or include `name` in the JSON file
|
|
132
|
+
- **"Scope is required in CI mode"** — Add `--scope x_cadso_core` when using `--ci`
|
|
133
|
+
- **"Failed to create record"** — Check that the `api/cadso/dovetail/createRecord` endpoint exists on the target instance
|
|
134
|
+
- **"Local sync failed"** — Record was created on instance. Run `npx dove refresh` to pull it manually
|
|
135
|
+
- **Record not in expected update set** — Verify `.dove-update-sets.json` has the correct scope mapping. Use `npx dove currentUpdateSet` to check
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
# Debug Dovetail Build Transformations
|
|
2
|
+
|
|
3
|
+
## Task
|
|
4
|
+
$ARGUMENTS
|
|
5
|
+
|
|
6
|
+
## Instructions for Claude
|
|
7
|
+
|
|
8
|
+
### Directory Context
|
|
9
|
+
|
|
10
|
+
Dovetail commands can be run from two locations:
|
|
11
|
+
- **From `ServiceNow/` directory:** `npx sinc <command>`
|
|
12
|
+
- **From Craftsman root:** `npm run sinc:<command>` (proxy scripts)
|
|
13
|
+
|
|
14
|
+
Available root scripts: `sinc:init`, `sinc:start`, `sinc:dev`, `sinc:build`, `sinc:deploy`, `sinc:push`, `sinc:refresh`, `sinc:status`
|
|
15
|
+
|
|
16
|
+
When this skill references `npx sinc <command>`, use `npm run sinc:<command>` if working from the Craftsman root. The `build/` and `src/` directories referenced below are at `ServiceNow/build/` and `ServiceNow/src/` relative to the Craftsman root.
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
Help the user understand, inspect, or debug the Dovetail build transformation pipeline -- what happens between source code and what reaches ServiceNow.
|
|
21
|
+
|
|
22
|
+
### Step 1: Run a Local Build
|
|
23
|
+
|
|
24
|
+
To see build output without pushing to ServiceNow:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
npx dove build
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Output files appear in the `build/` directory (configured via `buildDirectory` in `dove.config.js`), mirroring the source directory structure.
|
|
31
|
+
|
|
32
|
+
To build only changed files (compared to a git branch):
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
npx dove build --diff main
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### Step 2: Compare Source vs Output
|
|
39
|
+
|
|
40
|
+
```
|
|
41
|
+
src/sys_script_include/MyScript/script.ts <-- Source (TypeScript)
|
|
42
|
+
build/sys_script_include/MyScript/script.ts <-- Output (transpiled JS)
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### Step 3: Understand Transformation Stages
|
|
46
|
+
|
|
47
|
+
For a typical TypeScript server-side pipeline (`typescript-plugin` + `babel-plugin`):
|
|
48
|
+
|
|
49
|
+
**Stage 1: TypeScript Plugin** (`transpile: false`)
|
|
50
|
+
- Runs the TypeScript compiler for type checking only
|
|
51
|
+
- Does NOT modify the code
|
|
52
|
+
- Errors here = TypeScript type errors
|
|
53
|
+
|
|
54
|
+
**Stage 2: Babel Plugin** (with presets and plugins)
|
|
55
|
+
|
|
56
|
+
Babel plugins run first (in order):
|
|
57
|
+
1. `@tenonhq/dovetail-remove-modules` -- Strips `import`/`export` statements
|
|
58
|
+
2. `@babel/proposal-class-properties` -- Transforms class property syntax
|
|
59
|
+
3. `@babel/proposal-object-rest-spread` -- Transforms `...spread` syntax
|
|
60
|
+
|
|
61
|
+
Babel presets run in reverse order:
|
|
62
|
+
1. `@babel/typescript` (listed last, runs first) -- Strips type annotations
|
|
63
|
+
2. `@babel/env` -- Transpiles ES6+ to ES5
|
|
64
|
+
3. `@tenonhq/dovetail-servicenow` (listed first, runs last) -- Sanitizes for Rhino: replaces `__proto__` with `__proto_sn__`, converts `obj.default` to `obj["default"]`
|
|
65
|
+
|
|
66
|
+
### Step 4: Diagnose Common Issues
|
|
67
|
+
|
|
68
|
+
**"Cannot read property 'X' of undefined" in ServiceNow**
|
|
69
|
+
- Likely: `import` statements were not removed. Check that `@tenonhq/dovetail-remove-modules` is in Babel plugins.
|
|
70
|
+
- The import variable becomes `undefined` because ServiceNow has no module system.
|
|
71
|
+
|
|
72
|
+
**"Illegal access to reserved word" in ServiceNow**
|
|
73
|
+
- Likely: Missing `@tenonhq/dovetail-servicenow` preset. Code like `obj.default` or `obj.class` crashes Rhino.
|
|
74
|
+
- Fix: Ensure `@tenonhq/dovetail-servicenow` is the FIRST preset listed (= runs LAST).
|
|
75
|
+
|
|
76
|
+
**"__proto__" security error in ServiceNow**
|
|
77
|
+
- Likely: Missing `@tenonhq/dovetail-servicenow` preset. Babel's class transpilation generates `__proto__` references.
|
|
78
|
+
|
|
79
|
+
**"TypeError: Cannot extend a non-class" or prototype errors**
|
|
80
|
+
- Likely: Using `useBuiltIns` with `@babel/env`. Rhino locks base class prototypes.
|
|
81
|
+
- Fix: Remove `useBuiltIns` from `@babel/env` config.
|
|
82
|
+
|
|
83
|
+
**Build succeeds but code does nothing in ServiceNow**
|
|
84
|
+
- Check if `export default` was on the main class/function. The `remove-modules` plugin strips exports. In ServiceNow script includes, the class/function name must match the script include name.
|
|
85
|
+
|
|
86
|
+
### Special Comment Tags
|
|
87
|
+
|
|
88
|
+
The `@tenonhq/dovetail-remove-modules` Babel plugin supports these comment tags:
|
|
89
|
+
|
|
90
|
+
**`@keepModule`** -- Preserve an import (for actual ServiceNow modules):
|
|
91
|
+
```javascript
|
|
92
|
+
//@keepModule
|
|
93
|
+
import moduleDos from "myModuleDos";
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
**`@expandModule`** -- Expand imports to dot notation:
|
|
97
|
+
```javascript
|
|
98
|
+
//@expandModule
|
|
99
|
+
import { helper } from "x_cadso_core";
|
|
100
|
+
// becomes: x_cadso_core.helper
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
**`@moduleAlias=newName`** -- Rename the module reference with `@expandModule`:
|
|
104
|
+
```javascript
|
|
105
|
+
//@expandModule
|
|
106
|
+
//@moduleAlias=MyApp
|
|
107
|
+
import { helper } from "x_cadso_core";
|
|
108
|
+
// becomes: MyApp.helper
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### Step 5: Test Incrementally
|
|
112
|
+
|
|
113
|
+
If you cannot determine which stage causes an issue:
|
|
114
|
+
|
|
115
|
+
1. **Remove all plugins** from the rule and push raw source -- does it work?
|
|
116
|
+
2. **Add plugins back one at a time** and rebuild after each addition.
|
|
117
|
+
3. **Check the `build/` directory** after each rebuild to see intermediate output.
|