@enfocussw/switch-scripting-context 25.11.1-beta.5 → 25.11.1-beta.6
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/CHANGELOG.md +45 -0
- package/README.md +18 -9
- package/dist/init.d.ts +19 -1
- package/dist/init.js +114 -25
- package/docs/switch-api/api-versions.md +20 -9
- package/docs/switch-api/document-classes.md +11 -0
- package/docs/switch-api/entry-points.md +12 -0
- package/docs/switch-api/enums.md +17 -0
- package/docs/switch-api/execution-environment.md +45 -12
- package/docs/switch-api/flow-element.md +13 -0
- package/docs/switch-api/job-patterns.md +13 -0
- package/docs/switch-api/job.md +16 -1
- package/docs/switch-api/logging.md +15 -0
- package/docs/switch-api/switch.md +10 -0
- package/docs/switch-appstore/app-guidelines.md +19 -0
- package/docs/switch-project/node-versions.md +87 -0
- package/docs/switch-project/project-planning.md +25 -5
- package/docs/switch-project/property-editors.md +13 -1
- package/docs/switch-project/script-declaration.md +15 -0
- package/docs/switch-project/script-structure.md +22 -78
- package/docs/switch-project/tooling.md +12 -2
- package/docs/switch-project/vscode.md +3 -3
- package/docs/switch-scripting.md +7 -4
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,51 @@ All notable changes to this package are documented here. Format follows
|
|
|
5
5
|
|
|
6
6
|
## [Unreleased]
|
|
7
7
|
|
|
8
|
+
## [25.11.1-beta.6] - 2026-10-07
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- The Node.js version table now lists Switch 26.11, which runs scripts on Node.js 24.
|
|
13
|
+
- Every doc over 100 lines now opens with a Contents list of its section headings. An agent that
|
|
14
|
+
reads only the first part of a file can still see which sections exist further down.
|
|
15
|
+
- `--tools pi` configures the Pi coding agent. It is an alias for `codex`, because Pi reads the
|
|
16
|
+
same instructions file as Codex.
|
|
17
|
+
- `--tools continue` writes a Continue rule that is always in context, with the same rules and doc
|
|
18
|
+
list the other tools get.
|
|
19
|
+
- `--tools aider` adds the docs index to the read-only files Aider loads at startup. If your Aider
|
|
20
|
+
config already lists read-only files, `init` leaves it alone and prints the line to add.
|
|
21
|
+
|
|
22
|
+
### Changed
|
|
23
|
+
|
|
24
|
+
- The docs now list only publicly released Switch versions. Version tables drop unreleased builds,
|
|
25
|
+
and examples that named one now use Switch 25.11 or 26.11.
|
|
26
|
+
- The Node.js version table and the rules for `SwitchVersion` moved out of the script project
|
|
27
|
+
structure doc into their own doc, with its own row in the routing table. Agents
|
|
28
|
+
asking which Node.js version a script runs on now read only that section.
|
|
29
|
+
|
|
30
|
+
### Fixed
|
|
31
|
+
|
|
32
|
+
- The example of packing changing the Node.js version said a `SwitchVersion` of 21.0 runs on
|
|
33
|
+
Node.js 16. It runs on Node.js 14, as the version table already said.
|
|
34
|
+
- Agents often answered a short Switch question from the index page alone, without opening the doc
|
|
35
|
+
that holds the answer, and got it wrong. The generated instructions now tell agents to read the
|
|
36
|
+
matching doc before answering any Switch question, not only before writing code.
|
|
37
|
+
- The `Job` private data docs did not point to the string values of `EnfocusSwitchPrivateDataTag`,
|
|
38
|
+
so agents reported bare names such as `userEmail`. They now link to the enum reference.
|
|
39
|
+
- The property editor docs told readers to verify the `getLibraryForMultipleProperty` entry point
|
|
40
|
+
name "against source", which a consuming project does not have. The note now says the name is
|
|
41
|
+
unconfirmed.
|
|
42
|
+
- Re-running `init` stacked a second copy of the YAML frontmatter in the Cursor and Copilot
|
|
43
|
+
scoped-instructions files, one copy per run, which left the frontmatter invalid for both tools.
|
|
44
|
+
`init` now replaces its own frontmatter instead of prepending a new one, and leaves frontmatter
|
|
45
|
+
you have edited alone.
|
|
46
|
+
- An agent working in an already-scaffolded script folder skipped the Script vs App question. The
|
|
47
|
+
planning docs now say to ask it anyway, because a scaffolded manifest is always typed `Script`.
|
|
48
|
+
- The execution environment docs said top-level script variables survive between jobs and
|
|
49
|
+
suggested using them as a cache. The executor re-evaluates the script on every call, so they do
|
|
50
|
+
not. The docs now list what can leak (globals, `require()` caches, open handles) and say not to
|
|
51
|
+
rely on any of it.
|
|
52
|
+
|
|
8
53
|
## [25.11.1-beta.5] - 2026-09-21
|
|
9
54
|
|
|
10
55
|
### Fixed
|
package/README.md
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
AI coding assistant context for [Enfocus Switch](https://www.enfocus.com/en/switch) scripting projects (Node.js/TypeScript).
|
|
4
4
|
|
|
5
|
-
Installs curated API reference docs and generates config files for
|
|
5
|
+
Installs curated API reference docs and generates config files for 10 AI coding agents (Claude Code, GitHub Copilot, Cursor, Codex CLI/OpenCode/Pi, Gemini CLI, Windsurf, Zed, Cline, Continue, and Aider) so AI assistants understand the Switch scripting API out of the box.
|
|
6
6
|
|
|
7
|
-
See [CHANGELOG.md](https://cdn.jsdelivr.net/npm/@enfocussw/switch-scripting-context@25.11.1-beta.
|
|
7
|
+
See [CHANGELOG.md](https://cdn.jsdelivr.net/npm/@enfocussw/switch-scripting-context@25.11.1-beta.6/CHANGELOG.md) (also included in this package) for what's changed between versions.
|
|
8
8
|
|
|
9
9
|
## Usage
|
|
10
10
|
|
|
@@ -62,13 +62,20 @@ stay on the old name.
|
|
|
62
62
|
| GitHub Copilot | `.github/copilot-instructions.md` | `#file:` reference to hub |
|
|
63
63
|
| GitHub Copilot (scoped) | `.github/instructions/switch-scripting.instructions.md` | `applyTo: "**/*.ts"`; auto-attaches to every TypeScript file edit |
|
|
64
64
|
| Cursor | `.cursor/rules/switch-scripting.mdc` | Inline key rules + full API file path list |
|
|
65
|
-
| Codex CLI / OpenCode | `AGENTS.md` | Inline key rules + full API file path list |
|
|
65
|
+
| Codex CLI / OpenCode / Pi | `AGENTS.md` | Inline key rules + full API file path list |
|
|
66
66
|
| Gemini CLI | `GEMINI.md` | `@docs-for-agents/switch-scripting.md` import |
|
|
67
67
|
| Windsurf | `.windsurfrules` | Inline key rules + full API file path list |
|
|
68
68
|
| Zed | `.rules` | Inline key rules + full API file path list |
|
|
69
69
|
| Cline | `.clinerules` | Inline key rules + full API file path list |
|
|
70
|
+
| Continue | `.continue/rules/switch-scripting.md` | `alwaysApply: true`; inline key rules + full API file path list |
|
|
71
|
+
| Aider | `.aider.conf.yml` | `read:` entry that loads the hub file read-only at startup |
|
|
70
72
|
|
|
71
|
-
All files use `<!-- switch-scripting-context begin -->` / `<!-- switch-scripting-context end -->` markers. Re-running `init` replaces only the Switch section in existing files. Project-specific rules outside the markers are untouched.
|
|
73
|
+
All files use `<!-- switch-scripting-context begin -->` / `<!-- switch-scripting-context end -->` markers, or `# switch-scripting-context begin` / `# switch-scripting-context end` in `.aider.conf.yml`. Re-running `init` replaces only the Switch section in existing files. Project-specific rules outside the markers are untouched.
|
|
74
|
+
|
|
75
|
+
Two limits apply to Aider:
|
|
76
|
+
|
|
77
|
+
- Start Aider from the project root. Aider resolves the `read:` path against the folder it starts in, so from a subfolder it skips the file and prints an error.
|
|
78
|
+
- If your `.aider.conf.yml` already has a `read:` key, `init` leaves the file alone and prints the path to add to your list. A second `read:` key would replace your list, not extend it.
|
|
72
79
|
|
|
73
80
|
## Using this with your coding agent
|
|
74
81
|
|
|
@@ -89,7 +96,7 @@ A few things this gets you without asking for them by name:
|
|
|
89
96
|
properties (app path/licence) are off-limits and left to SwitchScripter's GUI instead.
|
|
90
97
|
|
|
91
98
|
Re-run `init` after upgrading this package so the copied docs and generated config files catch up.
|
|
92
|
-
See [CHANGELOG.md](https://cdn.jsdelivr.net/npm/@enfocussw/switch-scripting-context@25.11.1-beta.
|
|
99
|
+
See [CHANGELOG.md](https://cdn.jsdelivr.net/npm/@enfocussw/switch-scripting-context@25.11.1-beta.6/CHANGELOG.md) for what changed.
|
|
93
100
|
|
|
94
101
|
## Options
|
|
95
102
|
|
|
@@ -97,8 +104,9 @@ See [CHANGELOG.md](https://cdn.jsdelivr.net/npm/@enfocussw/switch-scripting-cont
|
|
|
97
104
|
npx switch-scripting-context init [options]
|
|
98
105
|
|
|
99
106
|
--tools <list> Tools to configure. Default: all
|
|
100
|
-
IDs: claude, copilot, cursor, codex, gemini, windsurf, zed, cline
|
|
101
|
-
|
|
107
|
+
IDs: claude, copilot, cursor, codex, gemini, windsurf, zed, cline,
|
|
108
|
+
continue, aider
|
|
109
|
+
Aliases: opencode, pi (→ codex), clawcode (→ claude)
|
|
102
110
|
--docs-dir <dir> Destination folder for docs. Default: docs-for-agents
|
|
103
111
|
--force Overwrite existing AI config files instead of merging
|
|
104
112
|
--dry-run Print what would happen without writing any files
|
|
@@ -152,7 +160,7 @@ The `docs-for-agents/` folder contains:
|
|
|
152
160
|
|
|
153
161
|
- `switch-scripting.md`: master index with execution environment rules and "load when" routing table
|
|
154
162
|
<!-- docs-index:readme begin -->
|
|
155
|
-
- `switch-project/project-planning.md`:
|
|
163
|
+
- `switch-project/project-planning.md`: Planning checklist, run before scaffolding or on a project that is already scaffolded: Script vs App, job-processing approach, one script folder or several, target OS, Switch version baseline, concurrency, native/binary npm dependencies, Appstore competition risk
|
|
156
164
|
- `switch-api/entry-points.md`: All entry point signatures, constraints, and when each is called
|
|
157
165
|
- `switch-api/switch.md`: `Switch` (`s`): global data, webhooks, abort, server utilities
|
|
158
166
|
- `switch-api/flow-element.md`: `FlowElement`: properties, connections, job creation, logging
|
|
@@ -161,7 +169,7 @@ The `docs-for-agents/` folder contains:
|
|
|
161
169
|
- `switch-api/http.md`: `HttpRequest` / `HttpResponse` + webhook pattern
|
|
162
170
|
- `switch-api/enums.md`: All enums with string values (`LogLevel`, `AccessLevel`, `DatasetModel`, `Scope`, `Priority`, `Connection.Level`, etc.)
|
|
163
171
|
- `switch-api/document-classes.md`: `PdfDocument`, `PdfPage`, `ImageDocument`, `XmlDocument`, `XmpDocument`: read-only file introspection
|
|
164
|
-
- `switch-project/script-structure.md`: What files a script folder contains, laying out several script folders side by side, `manifest.xml` format,
|
|
172
|
+
- `switch-project/script-structure.md`: What files a script folder contains, laying out several script folders side by side, `manifest.xml` format, Script vs App, packing an app with SwitchScripter
|
|
165
173
|
- `switch-project/tooling.md`: SwitchScriptTool commands and install paths, folder vs `.sscript` trade-offs, deployment
|
|
166
174
|
- `switch-project/debugging.md`: Enabling debug mode in Switch Designer, debuggable entry points, VS Code attach
|
|
167
175
|
- `switch-project/vscode.md`: Type declarations, tsconfig for TypeScript 6, ESLint rules
|
|
@@ -177,4 +185,5 @@ The `docs-for-agents/` folder contains:
|
|
|
177
185
|
- `switch-appstore/app-manual.md`: Writing guidance for the separate app manual document uploaded during Appstore review (`documentation-app_name.docx` template)
|
|
178
186
|
- `switch-appstore/app-store-submission.md`: Writing guidance for the Create Appstore App / Create Appstore App Version web forms: Short Description, What's new, Eula, icon specs, and which fields reuse content already written elsewhere
|
|
179
187
|
- `switch-api/api-versions.md`: Which Switch release added each scripting API class, method, and enum value; API availability follows the running Switch, not `manifest.xml`
|
|
188
|
+
- `switch-project/node-versions.md`: How `SwitchVersion` in `manifest.xml` selects the Node.js version, the version table per Switch release, which tools overwrite `SwitchVersion`, values missing from the table, other effects of `SwitchVersion`
|
|
180
189
|
<!-- docs-index:readme end -->
|
package/dist/init.d.ts
CHANGED
|
@@ -1,6 +1,17 @@
|
|
|
1
|
+
export interface Markers {
|
|
2
|
+
begin: string;
|
|
3
|
+
end: string;
|
|
4
|
+
}
|
|
1
5
|
export interface ToolFile {
|
|
2
6
|
targetPath: (root: string, docsDir: string) => string;
|
|
3
7
|
generate: (docsDir: string) => string;
|
|
8
|
+
/** Comment syntax around the generated section. Default: HTML comments, for Markdown files. */
|
|
9
|
+
markers?: Markers;
|
|
10
|
+
/**
|
|
11
|
+
* Checks an existing file that has no Switch section yet. Returns why appending one would break
|
|
12
|
+
* the file, or null when appending is safe. init then skips the file and prints the reason.
|
|
13
|
+
*/
|
|
14
|
+
appendConflict?: (existing: string, docsDir: string) => string | null;
|
|
4
15
|
}
|
|
5
16
|
export interface ToolDefinition {
|
|
6
17
|
id: string;
|
|
@@ -29,8 +40,15 @@ export declare function generateGeminiMd(docsDir: string): string;
|
|
|
29
40
|
export declare function generateWindsurfRules(docsDir: string): string;
|
|
30
41
|
export declare function generateZedRules(docsDir: string): string;
|
|
31
42
|
export declare function generateClineRules(docsDir: string): string;
|
|
43
|
+
export declare function generateContinueRule(docsDir: string): string;
|
|
44
|
+
export declare function generateAiderConf(docsDir: string): string;
|
|
45
|
+
/**
|
|
46
|
+
* A second top-level read key would not merge with the user's own: Aider keeps only the last
|
|
47
|
+
* one, so appending ours would silently drop every file the user already loads.
|
|
48
|
+
*/
|
|
49
|
+
export declare function aiderReadConflict(existing: string, docsDir: string): string | null;
|
|
32
50
|
export declare function buildIdMap(registry: ToolDefinition[]): Map<string, string>;
|
|
33
|
-
export declare function findMarkerRange(content: string): [number, number] | null;
|
|
51
|
+
export declare function findMarkerRange(content: string, markers?: Markers): [number, number] | null;
|
|
34
52
|
/** The running package's own version, so a git-clone install stamps what actually ran. */
|
|
35
53
|
export declare function packageVersion(root?: string): string;
|
|
36
54
|
/** The comment init writes as the first line of the copied hub file. */
|
package/dist/init.js
CHANGED
|
@@ -40,6 +40,9 @@ exports.generateGeminiMd = generateGeminiMd;
|
|
|
40
40
|
exports.generateWindsurfRules = generateWindsurfRules;
|
|
41
41
|
exports.generateZedRules = generateZedRules;
|
|
42
42
|
exports.generateClineRules = generateClineRules;
|
|
43
|
+
exports.generateContinueRule = generateContinueRule;
|
|
44
|
+
exports.generateAiderConf = generateAiderConf;
|
|
45
|
+
exports.aiderReadConflict = aiderReadConflict;
|
|
43
46
|
exports.buildIdMap = buildIdMap;
|
|
44
47
|
exports.findMarkerRange = findMarkerRange;
|
|
45
48
|
exports.packageVersion = packageVersion;
|
|
@@ -52,6 +55,12 @@ const readline = __importStar(require("readline"));
|
|
|
52
55
|
// ─── Markers ─────────────────────────────────────────────────────────────────
|
|
53
56
|
const MARKER_BEGIN = '<!-- switch-scripting-context begin -->';
|
|
54
57
|
const MARKER_END = '<!-- switch-scripting-context end -->';
|
|
58
|
+
const HTML_MARKERS = { begin: MARKER_BEGIN, end: MARKER_END };
|
|
59
|
+
// YAML has no HTML comments, so a YAML config file marks its section with # comments instead.
|
|
60
|
+
const YAML_MARKERS = {
|
|
61
|
+
begin: '# switch-scripting-context begin',
|
|
62
|
+
end: '# switch-scripting-context end',
|
|
63
|
+
};
|
|
55
64
|
// ─── Shared content (single source of truth for all generated tool files) ────
|
|
56
65
|
/** Package root, whether running from src/ (ts-node) or dist/. */
|
|
57
66
|
function packageRoot() {
|
|
@@ -84,6 +93,7 @@ function apiFiles(root) {
|
|
|
84
93
|
}
|
|
85
94
|
const INLINE_CORE_RULES = `## Core rules
|
|
86
95
|
|
|
96
|
+
- Read the matching file from the API reference list below before answering any question about Switch scripting, not only before writing code, including short and yes/no questions. These rules only summarise; Switch often differs from what general Node.js knowledge suggests.
|
|
87
97
|
- Entry point functions are top-level async functions — do NOT use \`export\`, arrow functions, or class methods; declare them with the literal \`function\` keyword.
|
|
88
98
|
- Switch finds entry points with a regex, not a parser. Never write a string literal whose content ends with a backslash, a regex literal, or division outside the plain \`word / word\` shape — each silently deletes a span of real code and the entry points inside it, with no error. Read \`entry-points.md\` § Entry-point scanner constraints before editing \`main.ts\`/\`main.js\`.
|
|
89
99
|
- Every \`jobArrived\` must end with exactly one \`job.sendTo*()\` or \`job.fail()\`.
|
|
@@ -95,11 +105,12 @@ const INLINE_CORE_RULES = `## Core rules
|
|
|
95
105
|
// ─── Content generators ──────────────────────────────────────────────────────
|
|
96
106
|
// Claude Code and Gemini CLI resolve @file imports themselves, so their generated
|
|
97
107
|
// block is just a pointer to switch-scripting.md; the routing table and key rules
|
|
98
|
-
// living there are the actual instructions. Codex, Windsurf, Zed, and
|
|
99
|
-
// reliably follow that import syntax, so their generators (generateInlineBlock)
|
|
108
|
+
// living there are the actual instructions. Codex, Windsurf, Zed, Cline, and Continue
|
|
109
|
+
// don't reliably follow that import syntax, so their generators (generateInlineBlock)
|
|
100
110
|
// paste INLINE_CORE_RULES and the routing table directly into the generated file
|
|
101
|
-
// instead.
|
|
102
|
-
//
|
|
111
|
+
// instead. Aider has no instructions file at all; its config loads the hub as a
|
|
112
|
+
// read-only file. Don't collapse these into one shared generator; the split is
|
|
113
|
+
// deliberate, not duplication.
|
|
103
114
|
function generateClaudeMd(docsDir) {
|
|
104
115
|
return `${MARKER_BEGIN}
|
|
105
116
|
## Switch Scripting (Enfocus Switch)
|
|
@@ -112,7 +123,7 @@ function generateCopilotInstructions(docsDir) {
|
|
|
112
123
|
## Switch Scripting (Enfocus Switch)
|
|
113
124
|
|
|
114
125
|
This project uses Enfocus Switch scripting (Node.js/TypeScript).
|
|
115
|
-
Consult the Switch scripting reference before writing or modifying code.
|
|
126
|
+
Consult the Switch scripting reference before answering questions about Switch scripting or writing or modifying code.
|
|
116
127
|
|
|
117
128
|
#file:../${docsDir}/switch-scripting.md
|
|
118
129
|
${MARKER_END}`;
|
|
@@ -200,6 +211,38 @@ function generateClineRules(docsDir) {
|
|
|
200
211
|
${generateInlineBlock(docsDir)}
|
|
201
212
|
${MARKER_END}`;
|
|
202
213
|
}
|
|
214
|
+
// Continue reads every Markdown file in .continue/rules/. alwaysApply keeps the rules in context
|
|
215
|
+
// for questions too, not only when a matching file is open.
|
|
216
|
+
function generateContinueRule(docsDir) {
|
|
217
|
+
return `---
|
|
218
|
+
name: Switch scripting
|
|
219
|
+
description: Enfocus Switch scripting rules and API reference for Node.js/TypeScript scripts
|
|
220
|
+
alwaysApply: true
|
|
221
|
+
---
|
|
222
|
+
|
|
223
|
+
${MARKER_BEGIN}
|
|
224
|
+
## Switch Scripting (Enfocus Switch)
|
|
225
|
+
|
|
226
|
+
${generateInlineBlock(docsDir)}
|
|
227
|
+
${MARKER_END}`;
|
|
228
|
+
}
|
|
229
|
+
// Aider resolves a relative read path against the folder it was started from, not the git root,
|
|
230
|
+
// so this entry only works when Aider starts at the project root.
|
|
231
|
+
function generateAiderConf(docsDir) {
|
|
232
|
+
return `${YAML_MARKERS.begin}
|
|
233
|
+
read:
|
|
234
|
+
- ${docsDir}/switch-scripting.md
|
|
235
|
+
${YAML_MARKERS.end}`;
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* A second top-level read key would not merge with the user's own: Aider keeps only the last
|
|
239
|
+
* one, so appending ours would silently drop every file the user already loads.
|
|
240
|
+
*/
|
|
241
|
+
function aiderReadConflict(existing, docsDir) {
|
|
242
|
+
if (!/^read\s*:/m.test(existing))
|
|
243
|
+
return null;
|
|
244
|
+
return `it already has a read: key. Add ${docsDir}/switch-scripting.md to that list yourself.`;
|
|
245
|
+
}
|
|
203
246
|
// ─── Tool registry ───────────────────────────────────────────────────────────
|
|
204
247
|
const TOOL_REGISTRY = [
|
|
205
248
|
{
|
|
@@ -240,8 +283,8 @@ const TOOL_REGISTRY = [
|
|
|
240
283
|
},
|
|
241
284
|
{
|
|
242
285
|
id: 'codex',
|
|
243
|
-
label: 'Codex CLI / OpenCode',
|
|
244
|
-
altIds: ['opencode'],
|
|
286
|
+
label: 'Codex CLI / OpenCode / Pi',
|
|
287
|
+
altIds: ['opencode', 'pi'],
|
|
245
288
|
files: [
|
|
246
289
|
{
|
|
247
290
|
targetPath: (root) => path.join(root, 'AGENTS.md'),
|
|
@@ -289,6 +332,28 @@ const TOOL_REGISTRY = [
|
|
|
289
332
|
},
|
|
290
333
|
],
|
|
291
334
|
},
|
|
335
|
+
{
|
|
336
|
+
id: 'continue',
|
|
337
|
+
label: 'Continue',
|
|
338
|
+
files: [
|
|
339
|
+
{
|
|
340
|
+
targetPath: (root) => path.join(root, '.continue', 'rules', 'switch-scripting.md'),
|
|
341
|
+
generate: generateContinueRule,
|
|
342
|
+
},
|
|
343
|
+
],
|
|
344
|
+
},
|
|
345
|
+
{
|
|
346
|
+
id: 'aider',
|
|
347
|
+
label: 'Aider',
|
|
348
|
+
files: [
|
|
349
|
+
{
|
|
350
|
+
targetPath: (root) => path.join(root, '.aider.conf.yml'),
|
|
351
|
+
generate: generateAiderConf,
|
|
352
|
+
markers: YAML_MARKERS,
|
|
353
|
+
appendConflict: aiderReadConflict,
|
|
354
|
+
},
|
|
355
|
+
],
|
|
356
|
+
},
|
|
292
357
|
];
|
|
293
358
|
// ─── ID map ──────────────────────────────────────────────────────────────────
|
|
294
359
|
function buildIdMap(registry) {
|
|
@@ -301,16 +366,18 @@ function buildIdMap(registry) {
|
|
|
301
366
|
return map;
|
|
302
367
|
}
|
|
303
368
|
// ─── Merge logic ─────────────────────────────────────────────────────────────
|
|
304
|
-
function findMarkerRange(content) {
|
|
305
|
-
const begin = content.indexOf(
|
|
306
|
-
const end = content.indexOf(
|
|
369
|
+
function findMarkerRange(content, markers = HTML_MARKERS) {
|
|
370
|
+
const begin = content.indexOf(markers.begin);
|
|
371
|
+
const end = content.indexOf(markers.end);
|
|
307
372
|
if (begin === -1 || end === -1)
|
|
308
373
|
return null;
|
|
309
374
|
if (begin >= end)
|
|
310
375
|
return null;
|
|
311
|
-
return [begin, end +
|
|
376
|
+
return [begin, end + markers.end.length];
|
|
312
377
|
}
|
|
313
|
-
function resolveFileAction(targetPath,
|
|
378
|
+
function resolveFileAction(targetPath, file, docsDir, force) {
|
|
379
|
+
const block = file.generate(docsDir);
|
|
380
|
+
const markers = file.markers ?? HTML_MARKERS;
|
|
314
381
|
if (!fs.existsSync(targetPath)) {
|
|
315
382
|
return { path: targetPath, action: 'create', content: block };
|
|
316
383
|
}
|
|
@@ -318,16 +385,40 @@ function resolveFileAction(targetPath, block, force) {
|
|
|
318
385
|
return { path: targetPath, action: 'overwrite', content: block };
|
|
319
386
|
}
|
|
320
387
|
const existing = fs.readFileSync(targetPath, 'utf8');
|
|
321
|
-
const range = findMarkerRange(existing);
|
|
388
|
+
const range = findMarkerRange(existing, markers);
|
|
322
389
|
if (range) {
|
|
323
|
-
|
|
390
|
+
// The Cursor .mdc and Copilot scoped-instructions blocks carry frontmatter above the marker,
|
|
391
|
+
// and only the marker range is replaced. Writing the block whole would stack a second copy of
|
|
392
|
+
// that frontmatter on every re-run, so drop one of the two copies.
|
|
393
|
+
const frontmatter = block.slice(0, block.indexOf(markers.begin)).trim();
|
|
394
|
+
let before = existing.slice(0, range[0]);
|
|
395
|
+
let incoming = block;
|
|
396
|
+
if (frontmatter) {
|
|
397
|
+
if (before.replace(/\r\n/g, '\n').trim() === frontmatter) {
|
|
398
|
+
before = ''; // our own frontmatter from an earlier run; the block's copy replaces it
|
|
399
|
+
}
|
|
400
|
+
else {
|
|
401
|
+
// User-written or user-edited frontmatter, or init appended below the user's own content.
|
|
402
|
+
// Leave what is there and write only the marker section.
|
|
403
|
+
incoming = block.slice(block.indexOf(markers.begin));
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
const updated = before + incoming + existing.slice(range[1]);
|
|
324
407
|
return { path: targetPath, action: 'merge-replace', content: updated };
|
|
325
408
|
}
|
|
409
|
+
const reason = file.appendConflict?.(existing, docsDir);
|
|
410
|
+
if (reason) {
|
|
411
|
+
return { path: targetPath, action: 'skip', content: existing, reason };
|
|
412
|
+
}
|
|
326
413
|
const separator = existing.endsWith('\n') ? '\n' : '\n\n';
|
|
327
414
|
return { path: targetPath, action: 'merge-append', content: existing + separator + block + '\n' };
|
|
328
415
|
}
|
|
329
416
|
function applyFileAction(action, dryRun) {
|
|
330
417
|
const rel = path.relative(process.cwd(), action.path);
|
|
418
|
+
if (action.action === 'skip') {
|
|
419
|
+
console.log(` ${rel} → skipped: ${action.reason}`);
|
|
420
|
+
return;
|
|
421
|
+
}
|
|
331
422
|
const label = action.action === 'create' ? 'created'
|
|
332
423
|
: action.action === 'overwrite' ? 'overwritten'
|
|
333
424
|
: action.action === 'merge-replace' ? 'updated (replaced Switch section)'
|
|
@@ -458,7 +549,7 @@ function aiConfigFiles(targetRoot, docsDir, tools) {
|
|
|
458
549
|
/** The frontmatter a generator writes above the marker, trimmed; empty if it writes none. */
|
|
459
550
|
function generatedFrontmatter(file, docsDir) {
|
|
460
551
|
const generated = file.generate(docsDir);
|
|
461
|
-
return generated.slice(0, generated.indexOf(
|
|
552
|
+
return generated.slice(0, generated.indexOf((file.markers ?? HTML_MARKERS).begin)).trim();
|
|
462
553
|
}
|
|
463
554
|
/** Deletes now-empty folders from dir upwards, stopping at targetRoot. */
|
|
464
555
|
function removeEmptyDirs(dir, targetRoot) {
|
|
@@ -473,13 +564,13 @@ function removeAiConfig(filePath, file, docsDir, targetRoot, dryRun) {
|
|
|
473
564
|
const raw = fs.readFileSync(filePath, 'utf8');
|
|
474
565
|
const eol = raw.includes('\r\n') ? '\r\n' : '\n';
|
|
475
566
|
const content = raw.replace(/\r\n/g, '\n');
|
|
476
|
-
const range = findMarkerRange(content);
|
|
567
|
+
const range = findMarkerRange(content, file.markers);
|
|
477
568
|
if (!range)
|
|
478
569
|
return; // nothing from us in this file
|
|
479
570
|
const rel = path.relative(process.cwd(), filePath);
|
|
480
571
|
let before = content.slice(0, range[0]).trim();
|
|
481
572
|
const after = content.slice(range[1]).trim();
|
|
482
|
-
// Copilot scoped instructions
|
|
573
|
+
// Copilot scoped instructions, Cursor .mdc, and Continue rules put frontmatter above the marker. Only an exact
|
|
483
574
|
// copy of what the generator writes counts as ours; edited or user-written frontmatter stays.
|
|
484
575
|
const ours = generatedFrontmatter(file, docsDir);
|
|
485
576
|
if (ours && before === ours) {
|
|
@@ -598,16 +689,13 @@ function init(options) {
|
|
|
598
689
|
if (!options.tools.includes(toolDef.id))
|
|
599
690
|
continue;
|
|
600
691
|
for (const f of toolDef.files) {
|
|
601
|
-
toolActions.push({
|
|
602
|
-
targetPath: f.targetPath(targetRoot, options.docsDir),
|
|
603
|
-
block: f.generate(options.docsDir),
|
|
604
|
-
});
|
|
692
|
+
toolActions.push({ targetPath: f.targetPath(targetRoot, options.docsDir), file: f });
|
|
605
693
|
}
|
|
606
694
|
}
|
|
607
695
|
if (toolActions.length > 0) {
|
|
608
696
|
console.log('\nGenerating AI config files...');
|
|
609
|
-
for (const { targetPath,
|
|
610
|
-
const action = resolveFileAction(targetPath,
|
|
697
|
+
for (const { targetPath, file } of toolActions) {
|
|
698
|
+
const action = resolveFileAction(targetPath, file, options.docsDir, options.force);
|
|
611
699
|
applyFileAction(action, options.dryRun);
|
|
612
700
|
}
|
|
613
701
|
}
|
|
@@ -705,8 +793,9 @@ Commands:
|
|
|
705
793
|
|
|
706
794
|
Options (init):
|
|
707
795
|
--tools <list> Comma-separated tools to configure
|
|
708
|
-
IDs: claude, copilot, cursor, codex, gemini, windsurf, zed, cline
|
|
709
|
-
|
|
796
|
+
IDs: claude, copilot, cursor, codex, gemini, windsurf, zed, cline,
|
|
797
|
+
continue, aider
|
|
798
|
+
Aliases: opencode, pi (→ codex), clawcode (→ claude)
|
|
710
799
|
Default: all tools
|
|
711
800
|
--docs-dir <dir> Destination folder for docs in target project (default: docs-for-agents)
|
|
712
801
|
--force Overwrite existing AI config files rather than merging
|
|
@@ -9,18 +9,30 @@ triggers:
|
|
|
9
9
|
|
|
10
10
|
# API availability by Switch version
|
|
11
11
|
|
|
12
|
+
<!-- docs-index:contents begin -->
|
|
13
|
+
## Contents
|
|
14
|
+
|
|
15
|
+
- The running Switch decides which methods exist
|
|
16
|
+
- Checking at runtime
|
|
17
|
+
- Release names
|
|
18
|
+
- Source and limits of this list
|
|
19
|
+
- Baseline (every Switch version with Node.js scripting)
|
|
20
|
+
- Added per release
|
|
21
|
+
- Declaration changes to existing methods
|
|
22
|
+
<!-- docs-index:contents end -->
|
|
23
|
+
|
|
12
24
|
## The running Switch decides which methods exist
|
|
13
25
|
|
|
14
26
|
Each Switch installation ships one copy of the scripting module, and every bundled Node.js version
|
|
15
27
|
uses that same copy. So which API methods a script can call depends on the Switch Server the script
|
|
16
28
|
runs on, not on anything in the script package. A script whose `manifest.xml` says `20.1` runs on
|
|
17
|
-
Node.js 12 in Switch 26.
|
|
29
|
+
Node.js 12 in Switch 26.11, and it still gets the full 26.11 API.
|
|
18
30
|
|
|
19
31
|
The two versions are independent:
|
|
20
32
|
|
|
21
33
|
| Depends on | Decided by |
|
|
22
34
|
|---|---|
|
|
23
|
-
| Node.js version (language features, Node built-ins) | `SwitchVersion` in `manifest.xml`, looked up by the running Switch. See [
|
|
35
|
+
| Node.js version (language features, Node built-ins) | `SwitchVersion` in `manifest.xml`, looked up by the running Switch. See [node-versions.md](../switch-project/node-versions.md) |
|
|
24
36
|
| Scripting API (classes, methods, enum values below) | The version of the Switch Server the script runs on |
|
|
25
37
|
|
|
26
38
|
When code must run on an older Switch, check every API call against the tables below for the
|
|
@@ -54,10 +66,8 @@ if (typeof job.getVariableAsString === 'function') {
|
|
|
54
66
|
| `23.1` | Switch 2023 Fall |
|
|
55
67
|
| `24.0` | Switch 2024 Spring |
|
|
56
68
|
| `24.1` | Switch 2024 Fall |
|
|
57
|
-
| `25.07` | Switch 25.07 |
|
|
58
69
|
| `25.11` | Switch 25.11 |
|
|
59
|
-
| `26.
|
|
60
|
-
| `26.07` | Switch 26.07 |
|
|
70
|
+
| `26.11` | Switch 26.11 |
|
|
61
71
|
|
|
62
72
|
## Source and limits of this list
|
|
63
73
|
|
|
@@ -72,9 +82,10 @@ nothing.
|
|
|
72
82
|
that runs Node.js scripts.
|
|
73
83
|
- Tag 1.1.0 (May 2021) is Switch 2021 Spring. The later tags carry the release number (21.1.x,
|
|
74
84
|
22.0.x, 22.1.x, 24.0.x, 24.1.x).
|
|
75
|
-
- The declarations end at v24.1.1-final (Switch 2024 Fall). SwitchScriptTool 26.
|
|
76
|
-
that version. A check of the
|
|
77
|
-
value that v24.1.1 lacks
|
|
85
|
+
- The declarations end at v24.1.1-final (Switch 2024 Fall). SwitchScriptTool 26.11 still scaffolds
|
|
86
|
+
that version. A check of the scripting module in a pre-release Switch build found no public class,
|
|
87
|
+
method, or enum value that v24.1.1 lacks, and 26.11 adds no scripting API. So nothing was added in
|
|
88
|
+
23.1, 25.11, or 26.11.
|
|
78
89
|
- Entry points aren't part of the type declarations, so this list doesn't record when each entry
|
|
79
90
|
point appeared. The webhook entry points (`httpRequestTriggeredSync`/`Async`) need
|
|
80
91
|
`s.httpRequestSubscribe()`, so they can't be used before Switch 21.1 either.
|
|
@@ -100,7 +111,7 @@ nothing.
|
|
|
100
111
|
| 23.1 | Nothing |
|
|
101
112
|
| 24.0 | `flowElement.getScriptDataPath()`, `flowElement.createPathWithName()`; `job.getVariableAsString()`, `job.getxmlData()`, `job.getxmpData()`, `job.getJdfData()`, `job.getJSONData()`; `s.getPreferenceSetting()`, `s.getServerVersion()`; `NoYesListPropertyStringValue` |
|
|
102
113
|
| 24.1 | `connection.getType()`, `connection.getFileCount()`, `flowElement.getFileCount()` |
|
|
103
|
-
| 25.
|
|
114
|
+
| 25.11, 26.11 | Nothing |
|
|
104
115
|
|
|
105
116
|
## Declaration changes to existing methods
|
|
106
117
|
|
|
@@ -13,6 +13,17 @@ Read-only document introspection utilities. All methods may throw — wrap in `t
|
|
|
13
13
|
|
|
14
14
|
Each class needs a minimum Switch version: `PdfDocument` and `PdfPage` 21.0+, `ImageDocument` 21.1+, `XmlDocument` 22.0+, `XmpDocument` and `doc.getXMP()` 22.1+.
|
|
15
15
|
|
|
16
|
+
<!-- docs-index:contents begin -->
|
|
17
|
+
## Contents
|
|
18
|
+
|
|
19
|
+
- PdfDocument
|
|
20
|
+
- Static page dimension methods
|
|
21
|
+
- PdfPage
|
|
22
|
+
- ImageDocument
|
|
23
|
+
- XmlDocument
|
|
24
|
+
- XmpDocument
|
|
25
|
+
<!-- docs-index:contents end -->
|
|
26
|
+
|
|
16
27
|
## PdfDocument
|
|
17
28
|
|
|
18
29
|
Open a PDF to inspect metadata and page geometry.
|
|
@@ -11,6 +11,18 @@ triggers:
|
|
|
11
11
|
|
|
12
12
|
Entry points are top-level `async` functions with specific names. They are **not exported**. Switch calls them automatically based on flow events.
|
|
13
13
|
|
|
14
|
+
<!-- docs-index:contents begin -->
|
|
15
|
+
## Contents
|
|
16
|
+
|
|
17
|
+
- Entry-point scanner constraints
|
|
18
|
+
- Flow lifecycle
|
|
19
|
+
- Timer
|
|
20
|
+
- Job processing
|
|
21
|
+
- Webhooks
|
|
22
|
+
- Script expression
|
|
23
|
+
- Property UI callbacks
|
|
24
|
+
<!-- docs-index:contents end -->
|
|
25
|
+
|
|
14
26
|
## Entry-point scanner constraints
|
|
15
27
|
|
|
16
28
|
Switch discovers a script's entry points by regex, not by parsing. Before matching
|
package/docs/switch-api/enums.md
CHANGED
|
@@ -11,6 +11,23 @@ triggers:
|
|
|
11
11
|
|
|
12
12
|
All enums are available globally in `main.ts`. They are also accessible via `EnfocusSwitch.*` when used outside `main.ts` (e.g. in imported modules). Enums and values without a Switch version below exist in every Switch version with Node.js scripting; see [api-versions.md](api-versions.md).
|
|
13
13
|
|
|
14
|
+
<!-- docs-index:contents begin -->
|
|
15
|
+
## Contents
|
|
16
|
+
|
|
17
|
+
- LogLevel
|
|
18
|
+
- AccessLevel
|
|
19
|
+
- DatasetModel
|
|
20
|
+
- Scope
|
|
21
|
+
- Priority
|
|
22
|
+
- Connection.Level
|
|
23
|
+
- HttpRequest.Method
|
|
24
|
+
- PropertyType
|
|
25
|
+
- NoYesListPropertyStringValue
|
|
26
|
+
- EnfocusSwitchPrivateDataTag
|
|
27
|
+
- ImageDocument.ColorMode
|
|
28
|
+
- ImageDocument.ColorSpace
|
|
29
|
+
<!-- docs-index:contents end -->
|
|
30
|
+
|
|
14
31
|
## LogLevel
|
|
15
32
|
|
|
16
33
|
Used with `job.log()` and `flowElement.log()`.
|
|
@@ -13,6 +13,18 @@ How the Node.js process a script runs in behaves, beyond the entry point API its
|
|
|
13
13
|
execution mode below, these are consequences of the host process model rather than things a script
|
|
14
14
|
configures — understanding them avoids subtle bugs around state persistence and error handling.
|
|
15
15
|
|
|
16
|
+
<!-- docs-index:contents begin -->
|
|
17
|
+
## Contents
|
|
18
|
+
|
|
19
|
+
- Execution modes
|
|
20
|
+
- Two independent concurrency tiers
|
|
21
|
+
- Don't rely on in-memory state between entry point calls
|
|
22
|
+
- Unhandled promise rejections end the run, not the process
|
|
23
|
+
- Third-party npm modules: file-based scripts only
|
|
24
|
+
- Native (binary) addons are not supported
|
|
25
|
+
- No explicit CPU or memory cap beyond the documented thresholds
|
|
26
|
+
<!-- docs-index:contents end -->
|
|
27
|
+
|
|
16
28
|
## Execution modes
|
|
17
29
|
|
|
18
30
|
Set in the XML declaration via SwitchScripter, or by editing it directly (see
|
|
@@ -50,19 +62,40 @@ them:
|
|
|
50
62
|
recycled (see
|
|
51
63
|
[Executor cleanup thresholds](job-patterns.md#executor-cleanup-thresholds)).
|
|
52
64
|
|
|
53
|
-
##
|
|
65
|
+
## Don't rely on in-memory state between entry point calls
|
|
66
|
+
|
|
67
|
+
Write every entry point so it neither depends on state from an earlier call nor assumes it starts
|
|
68
|
+
from a clean process.
|
|
69
|
+
|
|
70
|
+
The executor evaluates the whole script again before every entry point call. Top-level
|
|
71
|
+
`let`/`const`/`var` declarations and functions in the script file are recreated each time, so a
|
|
72
|
+
counter or cache held in one does not carry over to the next job.
|
|
73
|
+
|
|
74
|
+
Some in-memory state can still outlive a call, because executor processes are long-lived and
|
|
75
|
+
shared:
|
|
76
|
+
|
|
77
|
+
- Properties set on `global`/`globalThis`. One executor runs code for every script element pooled
|
|
78
|
+
onto it, so a global can be read or overwritten by a different script.
|
|
79
|
+
- Internal state of CommonJS packages loaded with `require()`. Node caches a required module for
|
|
80
|
+
the life of the process, so a singleton inside the package (a client, a connection pool, a
|
|
81
|
+
configured default) can be reused by a later call. ES-module packages that are bundled into the
|
|
82
|
+
script (see [Native (binary) addons](#native-binary-addons-are-not-supported)) are evaluated
|
|
83
|
+
again on each call like the script itself.
|
|
84
|
+
- Timers, sockets, and other handles a call leaves open keep running after the entry point returns.
|
|
85
|
+
|
|
86
|
+
Whether any of this reaches a given job depends on which executor the job lands on and whether that
|
|
87
|
+
executor was recycled in between. A script cannot control or predict either. This is a side effect
|
|
88
|
+
of the process model, not a supported feature, and it can change between Switch versions:
|
|
54
89
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
job, and don't assume it's shared with an *arbitrary* other job either — reset explicitly at the
|
|
62
|
-
start of an entry point if a fresh value is required per job.
|
|
90
|
+
- Don't use globals or package-level singletons to cache data or pass it between jobs. Store data
|
|
91
|
+
that must outlive a call with `s.setGlobalData()` (see [switch.md](switch.md)) or on the job
|
|
92
|
+
itself.
|
|
93
|
+
- Don't set globals. If a package keeps internal state, configure it explicitly at the start of
|
|
94
|
+
each entry point rather than assuming either a fresh or a previously configured instance.
|
|
95
|
+
- Close connections, clear timers, and release file handles before the entry point returns.
|
|
63
96
|
|
|
64
|
-
`getInitialize()`/`getFinalize()`
|
|
65
|
-
|
|
97
|
+
The executor also recognises `getInitialize()`/`getFinalize()` functions in a script. They are not
|
|
98
|
+
part of the public scripting API; don't define them.
|
|
66
99
|
|
|
67
100
|
## Unhandled promise rejections end the run, not the process
|
|
68
101
|
|
|
@@ -85,7 +118,7 @@ third-party modules from its own `node_modules` folder (see
|
|
|
85
118
|
|
|
86
119
|
Scripts with ESM dependencies are bundled before execution, when `SwitchVersion` in `manifest.xml`
|
|
87
120
|
is `24.0` or higher (see
|
|
88
|
-
[
|
|
121
|
+
[node-versions.md § Other effects of `SwitchVersion`](../switch-project/node-versions.md#other-effects-of-switchversion)); this bundling path does not support
|
|
89
122
|
native/binary Node addons (`.node` files). Stick to pure-JavaScript/TypeScript dependencies.
|
|
90
123
|
|
|
91
124
|
## No explicit CPU or memory cap beyond the documented thresholds
|
|
@@ -11,6 +11,19 @@ triggers:
|
|
|
11
11
|
|
|
12
12
|
The `FlowElement` instance `flowElement` is passed to every entry point that operates on a flow element. It provides access to properties, connections, job creation, and logging.
|
|
13
13
|
|
|
14
|
+
<!-- docs-index:contents begin -->
|
|
15
|
+
## Contents
|
|
16
|
+
|
|
17
|
+
- Identity
|
|
18
|
+
- Properties
|
|
19
|
+
- Connections
|
|
20
|
+
- Timer
|
|
21
|
+
- Logging
|
|
22
|
+
- Job creation (jobArrived / timerFired / httpRequestTriggeredAsync)
|
|
23
|
+
- Channels
|
|
24
|
+
- Utilities
|
|
25
|
+
<!-- docs-index:contents end -->
|
|
26
|
+
|
|
14
27
|
## Identity
|
|
15
28
|
|
|
16
29
|
```ts
|
|
@@ -13,6 +13,19 @@ Common behavioral rules for file access, routing, temp file cleanup, and child j
|
|
|
13
13
|
|
|
14
14
|
---
|
|
15
15
|
|
|
16
|
+
<!-- docs-index:contents begin -->
|
|
17
|
+
## Contents
|
|
18
|
+
|
|
19
|
+
- File access semantics
|
|
20
|
+
- Temp file cleanup
|
|
21
|
+
- Platform-independent paths
|
|
22
|
+
- Sending jobs
|
|
23
|
+
- Dataset writes must precede child job creation
|
|
24
|
+
- processLater
|
|
25
|
+
- Executor cleanup thresholds
|
|
26
|
+
- Driving a third-party CLI application
|
|
27
|
+
<!-- docs-index:contents end -->
|
|
28
|
+
|
|
16
29
|
## File access semantics
|
|
17
30
|
|
|
18
31
|
`job.get(accessLevel)` and `job.getDataset(name, accessLevel)` behave differently depending on the access level:
|
package/docs/switch-api/job.md
CHANGED
|
@@ -11,6 +11,21 @@ triggers:
|
|
|
11
11
|
|
|
12
12
|
A `Job` represents a file or folder moving through the flow. It is passed to `jobArrived` and can be created via `flowElement.createJob()` or `job.createChild()`. Every job must be routed with a `sendTo*()` call or `fail()` before the entry point ends (or at a later time via `timerFired`).
|
|
13
13
|
> Jobs obtained via `flowElement.getJobs()` throw on `getPrivateData()`, `listDatasets()`, and `getDataset()` in the same entry point invocation — private data/metadata cannot be *read* back. `setPrivateData()`/`removePrivateData()` are not restricted this way.
|
|
14
|
+
|
|
15
|
+
<!-- docs-index:contents begin -->
|
|
16
|
+
## Contents
|
|
17
|
+
|
|
18
|
+
- Identity
|
|
19
|
+
- Priority
|
|
20
|
+
- File access
|
|
21
|
+
- Routing
|
|
22
|
+
- Failure & logging
|
|
23
|
+
- Child jobs
|
|
24
|
+
- Private data
|
|
25
|
+
- Datasets (metadata)
|
|
26
|
+
- Variables & structured data
|
|
27
|
+
<!-- docs-index:contents end -->
|
|
28
|
+
|
|
14
29
|
## Identity
|
|
15
30
|
|
|
16
31
|
```ts
|
|
@@ -108,7 +123,7 @@ Creates a new job inheriting the processing history, metadata, and private data
|
|
|
108
123
|
|
|
109
124
|
## Private data
|
|
110
125
|
|
|
111
|
-
Private data is arbitrary key/value storage attached to a job and passed along with it. `EnfocusSwitchPrivateDataTag` needs Switch 21.0+; before 21.0, store string values only (see [api-versions.md](api-versions.md#declaration-changes-to-existing-methods)).
|
|
126
|
+
Private data is arbitrary key/value storage attached to a job and passed along with it. `EnfocusSwitchPrivateDataTag` needs Switch 21.0+; before 21.0, store string values only (see [api-versions.md](api-versions.md#declaration-changes-to-existing-methods)). For each tag's string value (`"EnfocusSwitch.<name>"`) and the release that added it, see [enums.md § EnfocusSwitchPrivateDataTag](enums.md#enfocusswitchprivatedatatag).
|
|
112
127
|
|
|
113
128
|
```ts
|
|
114
129
|
job.getPrivateData(tag: string | EnfocusSwitchPrivateDataTag): Promise<any>
|
|
@@ -15,6 +15,21 @@ Guidance for using `job.log()`, `flowElement.log()`, `job.fail()`, and `flowElem
|
|
|
15
15
|
listed in [enums.md](enums.md). Each log call has a small performance overhead, so where
|
|
16
16
|
and how often to log is a deliberate choice, not a default.
|
|
17
17
|
|
|
18
|
+
<!-- docs-index:contents begin -->
|
|
19
|
+
## Contents
|
|
20
|
+
|
|
21
|
+
- Log levels
|
|
22
|
+
- Don't add a verbosity property
|
|
23
|
+
- Logging in loops
|
|
24
|
+
- `console.log` does not work
|
|
25
|
+
- Don't double-log before a failure
|
|
26
|
+
- Message formatting and the `%` gotcha
|
|
27
|
+
- Signature gotcha: array vs. single value
|
|
28
|
+
- Placeholders instead of concatenation
|
|
29
|
+
- Message quality
|
|
30
|
+
- Log volume
|
|
31
|
+
<!-- docs-index:contents end -->
|
|
32
|
+
|
|
18
33
|
## Log levels
|
|
19
34
|
|
|
20
35
|
| Level | Use for |
|
|
@@ -11,6 +11,16 @@ triggers:
|
|
|
11
11
|
|
|
12
12
|
The `Switch` instance `s` is passed to every entry point. It provides global data storage, webhook subscription, abort handling, and server utilities.
|
|
13
13
|
|
|
14
|
+
<!-- docs-index:contents begin -->
|
|
15
|
+
## Contents
|
|
16
|
+
|
|
17
|
+
- Global data
|
|
18
|
+
- Webhooks
|
|
19
|
+
- Abort
|
|
20
|
+
- Server utilities
|
|
21
|
+
- Translation extraction rules
|
|
22
|
+
<!-- docs-index:contents end -->
|
|
23
|
+
|
|
14
24
|
## Global data
|
|
15
25
|
|
|
16
26
|
Global data is key/value storage shared across entry point invocations, scoped by `Scope`.
|
|
@@ -25,6 +25,25 @@ Items fall into three tiers, marked on each one:
|
|
|
25
25
|
|
|
26
26
|
---
|
|
27
27
|
|
|
28
|
+
<!-- docs-index:contents begin -->
|
|
29
|
+
## Contents
|
|
30
|
+
|
|
31
|
+
- Properties
|
|
32
|
+
- Entry points
|
|
33
|
+
- Sending jobs
|
|
34
|
+
- Logging
|
|
35
|
+
- Temp files and paths
|
|
36
|
+
- App-only
|
|
37
|
+
- Identity and versioning
|
|
38
|
+
- Top-level declaration properties
|
|
39
|
+
- Password protection
|
|
40
|
+
- Localization
|
|
41
|
+
- Icon
|
|
42
|
+
- Extra files
|
|
43
|
+
- Source and review hygiene
|
|
44
|
+
- What review does and doesn't cover
|
|
45
|
+
<!-- docs-index:contents end -->
|
|
46
|
+
|
|
28
47
|
## Properties
|
|
29
48
|
|
|
30
49
|
- [ ] **Apps required / scripts recommended.** Every property name (`LocalizedTagName`) is 30
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: node-versions
|
|
3
|
+
category: switch-project
|
|
4
|
+
order: 26
|
|
5
|
+
summary: "How `SwitchVersion` in `manifest.xml` selects the Node.js version, the version table per Switch release, which tools overwrite `SwitchVersion`, values missing from the table, other effects of `SwitchVersion`"
|
|
6
|
+
triggers:
|
|
7
|
+
- "Working out which Node.js version a script or app will run on, or what `SwitchVersion` in manifest.xml does"
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Node.js version per Switch version
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
The Switch Server running the script picks its Node.js version by looking up `SwitchVersion` from
|
|
14
|
+
`manifest.xml` in a fixed table that ships with each Switch release:
|
|
15
|
+
|
|
16
|
+
| Switch version | `SwitchVersion` | Node.js used |
|
|
17
|
+
|---|---|---|
|
|
18
|
+
| Switch 2020 Spring | `20.0` | 12 |
|
|
19
|
+
| Switch 2020 Fall | `20.1` | 12 |
|
|
20
|
+
| Switch 2021 Spring | `21.0` | 14 |
|
|
21
|
+
| Switch 2021 Fall | `21.1` | 16 |
|
|
22
|
+
| Switch 2022 Spring | `22.0` | 16 |
|
|
23
|
+
| Switch 2022 Fall | `22.1` | 16 |
|
|
24
|
+
| Switch 2023 Fall | `23.1` | 18 |
|
|
25
|
+
| Switch 2024 Spring | `24.0` | 18 |
|
|
26
|
+
| Switch 2024 Fall | `24.1` | 20 |
|
|
27
|
+
| Switch 25.11 | `25.11` | 20 |
|
|
28
|
+
| Switch 26.11 | `26.11` | 24 |
|
|
29
|
+
|
|
30
|
+
Switch 26.11 bundles Node.js 12.22.12, 14.21.3, 16.20.2, 18.20.8, 20.20.0, and 24.13.0.
|
|
31
|
+
|
|
32
|
+
`SwitchVersion` controls the Node.js version only. Which scripting API methods exist depends on the
|
|
33
|
+
Switch version the script runs on, see [api-versions.md](../switch-api/api-versions.md).
|
|
34
|
+
|
|
35
|
+
## What writes `SwitchVersion`
|
|
36
|
+
|
|
37
|
+
`SwitchVersion` is the version of whichever tool last wrote the manifest. It is not a setting the
|
|
38
|
+
author picks:
|
|
39
|
+
|
|
40
|
+
- `SwitchScriptTool --create` writes the tool's own version into the new script folder.
|
|
41
|
+
- `SwitchScriptTool --pack` writes the tool's own version into the packed `.sscript`, whatever the
|
|
42
|
+
script folder's manifest says. The script folder's manifest itself is left unchanged. With
|
|
43
|
+
SwitchScriptTool 26.11, a folder whose manifest says `21.0` packs to a `.sscript` whose manifest
|
|
44
|
+
says `26.11`, which moves the script from Node.js 14 to Node.js 24. This was verified with a
|
|
45
|
+
pre-release SwitchScriptTool build.
|
|
46
|
+
- SwitchScripter writes its own version on every save. Opening a script with a different
|
|
47
|
+
`SwitchVersion` shows a warning that saving updates the script to the current Node.js version.
|
|
48
|
+
|
|
49
|
+
**Gotcha:** a script folder tested directly in Switch and the `.sscript` packed from it can run on
|
|
50
|
+
different Node.js versions. A folder created with an older SwitchScriptTool keeps that tool's
|
|
51
|
+
version, but packing it with a newer SwitchScriptTool stamps the newer one. Test the packed
|
|
52
|
+
`.sscript`, not only the folder, before shipping it.
|
|
53
|
+
|
|
54
|
+
To target an older Node.js version, pack the script with the SwitchScriptTool of a Switch release
|
|
55
|
+
whose row in the table gives that version. For example, a script packed with SwitchScriptTool 25.11
|
|
56
|
+
gets `SwitchVersion` `25.11` and runs on Node.js 20, in Switch 26.11 too. Apps work the same way
|
|
57
|
+
with SwitchScripter, except that there is no SwitchScripter for Switch 25.11. An app that
|
|
58
|
+
needs Node.js 20 is built with the Switch 2024 Fall SwitchScripter (`SwitchVersion` `24.1`), see
|
|
59
|
+
[script-structure.md § SwitchScripter and Switch version compatibility](script-structure.md#switchscripter-and-switch-version-compatibility).
|
|
60
|
+
Editing `SwitchVersion` by hand doesn't last, because `--pack` and SwitchScripter overwrite it.
|
|
61
|
+
|
|
62
|
+
## Values missing from the table
|
|
63
|
+
|
|
64
|
+
Behavior of the Switch 26.11 Server:
|
|
65
|
+
|
|
66
|
+
- No `SwitchVersion` element: treated as `20.1`, so Node.js 12.
|
|
67
|
+
- Lower than the first entry: Node.js 12.
|
|
68
|
+
- Higher than the last entry, for example a package built by a newer tool than the Switch it runs
|
|
69
|
+
on: the newest Node.js that Switch bundles. The Server logs a debug message that the script
|
|
70
|
+
"might not be compatible with the current Switch version" and runs it anyway.
|
|
71
|
+
- **Known issue:** a value that isn't an exact entry but falls numerically between the first and
|
|
72
|
+
last entries matches no Node.js version, for example `25.1` instead of `25.11`, `24.10` instead of
|
|
73
|
+
`24.1`, or `23.0`. The Server then fails to build the path to a Node.js binary, so no executor
|
|
74
|
+
process starts for the script. This was confirmed by running the Switch 26.11 lookup code with
|
|
75
|
+
these values, not by running such a script in Switch, so the exact symptom in Switch hasn't been
|
|
76
|
+
checked. A value such as `26.3` works today only because it's higher than the last entry, and it
|
|
77
|
+
will break once a later release adds an entry above it. Never hand-edit `SwitchVersion`. If you
|
|
78
|
+
must, copy a value exactly as the table above spells it.
|
|
79
|
+
|
|
80
|
+
## Other effects of `SwitchVersion`
|
|
81
|
+
|
|
82
|
+
- npm dependencies that are ES modules are bundled with esbuild before execution only when
|
|
83
|
+
`SwitchVersion` is `24.0` or higher.
|
|
84
|
+
- A script expression has no manifest. It always runs on the newest Node.js the running Switch
|
|
85
|
+
bundles.
|
|
86
|
+
|
|
87
|
+
> **Mac (Apple Silicon):** For scripts whose `SwitchVersion` is `21.1` (Switch 2021 Fall) or later, Switch runs the native ARM build of Node.js on Apple Silicon. Scripts with an earlier `SwitchVersion` run under Rosetta, because the bundled Node.js 12 and 14 are Intel-only builds. If a script bundles platform-specific binaries, ship both Intel and ARM variants.
|
|
@@ -2,15 +2,20 @@
|
|
|
2
2
|
id: project-planning
|
|
3
3
|
category: switch-project
|
|
4
4
|
order: 1
|
|
5
|
-
summary: "
|
|
5
|
+
summary: "Planning checklist, run before scaffolding or on a project that is already scaffolded: Script vs App, job-processing approach, one script folder or several, target OS, Switch version baseline, concurrency, native/binary npm dependencies, Appstore competition risk"
|
|
6
6
|
triggers:
|
|
7
|
-
- "Starting a new script or app, before scaffolding any files"
|
|
7
|
+
- "Starting a new script or app, before scaffolding any files, or working in a script folder that is already scaffolded where Script vs App has not been settled"
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# Project Planning
|
|
11
11
|
|
|
12
|
-
A
|
|
13
|
-
creating any files.
|
|
12
|
+
A planning checklist for a new script or app. Work through this with the user before
|
|
13
|
+
creating any files.
|
|
14
|
+
|
|
15
|
+
A script folder that already exists (scaffolded by the user, SwitchScripter, or `SwitchScriptTool
|
|
16
|
+
--create`) does not skip the checklist. The manifest's `ScriptPackageType` is always `Script` in a
|
|
17
|
+
scaffolded folder, so it does not answer item 1. Ask Script or App anyway, and run the other
|
|
18
|
+
checks against the code that exists. The goal is to make a few decisions deliberately up front, because retrofitting
|
|
14
19
|
them after code exists is expensive: password protection and localization for an app, path handling
|
|
15
20
|
for a second target OS, synchronizing shared-resource access for concurrency, or restructuring entry
|
|
16
21
|
points around a job-processing approach chosen too casually.
|
|
@@ -19,6 +24,21 @@ Two items below are direct questions for the user. The rest are not questions to
|
|
|
19
24
|
are checks the agent runs against what's actually being built, raised only when they become
|
|
20
25
|
relevant.
|
|
21
26
|
|
|
27
|
+
<!-- docs-index:contents begin -->
|
|
28
|
+
## Contents
|
|
29
|
+
|
|
30
|
+
- Ask the user directly
|
|
31
|
+
- 1. Script or App?
|
|
32
|
+
- 2. What should job processing look like in their flow?
|
|
33
|
+
- Evaluate and flag, don't ask upfront
|
|
34
|
+
- One script folder or several
|
|
35
|
+
- Target OS
|
|
36
|
+
- Switch version baseline (apps only)
|
|
37
|
+
- Concurrency
|
|
38
|
+
- Native or binary npm dependencies
|
|
39
|
+
- Appstore competition risk (apps only)
|
|
40
|
+
<!-- docs-index:contents end -->
|
|
41
|
+
|
|
22
42
|
## Ask the user directly
|
|
23
43
|
|
|
24
44
|
### 1. Script or App?
|
|
@@ -86,7 +106,7 @@ This sets two separate limits:
|
|
|
86
106
|
|
|
87
107
|
- Which SwitchScripter build is needed to produce a compatible `.enfpack`, and so which Node.js
|
|
88
108
|
version the app runs on (see
|
|
89
|
-
[
|
|
109
|
+
[node-versions.md](node-versions.md)).
|
|
90
110
|
Write code for that Node.js version.
|
|
91
111
|
- Which scripting API methods the code may call. Methods follow the Switch version the app runs on,
|
|
92
112
|
so check every call against [api-versions.md](../switch-api/api-versions.md) for the oldest
|
|
@@ -27,6 +27,18 @@ the order they're offered. `Type` follows from which editor(s) are chosen — se
|
|
|
27
27
|
|
|
28
28
|
---
|
|
29
29
|
|
|
30
|
+
<!-- docs-index:contents begin -->
|
|
31
|
+
## Contents
|
|
32
|
+
|
|
33
|
+
- Inline editors
|
|
34
|
+
- Modal editors
|
|
35
|
+
- Literal editors
|
|
36
|
+
- Extra XML attributes for certain editors
|
|
37
|
+
- Common practices
|
|
38
|
+
- A property whose shape varies by a type selector
|
|
39
|
+
- Notes
|
|
40
|
+
<!-- docs-index:contents end -->
|
|
41
|
+
|
|
30
42
|
## Inline editors
|
|
31
43
|
|
|
32
44
|
The inline editor slot is always the single token `inline` in `Editor` — what differs is `Type`.
|
|
@@ -60,7 +72,7 @@ open a dialog when the user clicks the editor button. All have `Type="string"` u
|
|
|
60
72
|
| `filetype` | Filename pattern(s) for the selected file type |
|
|
61
73
|
| `types` (`Type="filefilter"`) | `string[]` — one pattern string per selected file type |
|
|
62
74
|
| `askplugin` | String value selected from the library dialog (calls `getLibraryForProperty`) — **requires the script to implement `getLibraryForProperty`** (`getLibraryForConnectionProperty` for a connection field), see [entry-points.md](../switch-api/entry-points.md#property-ui-callbacks) |
|
|
63
|
-
| `askplugin2` | `string[]` — one string per selected library item (calls `getLibraryForMultipleProperty`) — **requires a matching library-callback entry point**, same as `askplugin` above. ⚠ `getLibraryForMultipleProperty` isn't documented anywhere in [entry-points.md](../switch-api/entry-points.md#property-ui-callbacks), which only lists `getLibraryForProperty`/`getLibraryForConnectionProperty` — this may be the same entry point handling both single- and multi-select, or a genuinely separate, undocumented one
|
|
75
|
+
| `askplugin2` | `string[]` — one string per selected library item (calls `getLibraryForMultipleProperty`) — **requires a matching library-callback entry point**, same as `askplugin` above. ⚠ `getLibraryForMultipleProperty` isn't documented anywhere in [entry-points.md](../switch-api/entry-points.md#property-ui-callbacks), which only lists `getLibraryForProperty`/`getLibraryForConnectionProperty` — this may be the same entry point handling both single- and multi-select, or a genuinely separate, undocumented one. Unconfirmed, so treat the name as unverified. |
|
|
64
76
|
| `description` | Multi-line text as a single string (may include newlines) |
|
|
65
77
|
| `scriptexp` | Result of script expression evaluated in job context, as a string |
|
|
66
78
|
| `sltextwithvar` | Single-line text with variables substituted, as a string |
|
|
@@ -13,6 +13,21 @@ The file `<ScriptID>.xml` defines the script's metadata, custom properties, conn
|
|
|
13
13
|
and execution configuration. It is normally written by **SwitchScripter**, but the format is fully
|
|
14
14
|
documented below — you can edit it directly.
|
|
15
15
|
|
|
16
|
+
<!-- docs-index:contents begin -->
|
|
17
|
+
## Contents
|
|
18
|
+
|
|
19
|
+
- Agent editing policy
|
|
20
|
+
- XML structure overview
|
|
21
|
+
- Built-in ElementFields
|
|
22
|
+
- Custom property elements (ElementFields)
|
|
23
|
+
- ConnectionFields
|
|
24
|
+
- ExtraProperties
|
|
25
|
+
- Type reference
|
|
26
|
+
- Escaped `ValueDescription` payloads
|
|
27
|
+
- Reserved tag names
|
|
28
|
+
- Annotated example
|
|
29
|
+
<!-- docs-index:contents end -->
|
|
30
|
+
|
|
16
31
|
## Agent editing policy
|
|
17
32
|
|
|
18
33
|
- Editing this file directly is safe as long as you follow the rules on this page exactly — the
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
id: script-structure
|
|
3
3
|
category: switch-project
|
|
4
4
|
order: 10
|
|
5
|
-
summary: "What files a script folder contains, laying out several script folders side by side, `manifest.xml` format,
|
|
5
|
+
summary: "What files a script folder contains, laying out several script folders side by side, `manifest.xml` format, Script vs App, packing an app with SwitchScripter"
|
|
6
6
|
triggers:
|
|
7
|
-
- "Setting up a new script project
|
|
7
|
+
- "Setting up a new script project or converting a Script to an App"
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# Script Project Structure
|
|
@@ -13,6 +13,20 @@ A Switch script project lives in a **script folder** during development and is d
|
|
|
13
13
|
|
|
14
14
|
> **Agent editing policy**: Edit TypeScript/JavaScript source files (`main.ts`, `main.js`) and the XML declaration (`<ScriptID>.xml`) freely — see [script-declaration.md](script-declaration.md) for the declaration's rules, and [entry-points.md § Entry-point scanner constraints](../switch-api/entry-points.md#entry-point-scanner-constraints) before writing any string/regex literal or division, since certain shapes make Switch's entry-point scanner silently drop functions. Leave `manifest.xml` to the user unless explicitly asked.
|
|
15
15
|
|
|
16
|
+
<!-- docs-index:contents begin -->
|
|
17
|
+
## Contents
|
|
18
|
+
|
|
19
|
+
- Script folder files
|
|
20
|
+
- Several script folders side by side
|
|
21
|
+
- manifest.xml format
|
|
22
|
+
- Node.js version per Switch version
|
|
23
|
+
- Script vs App
|
|
24
|
+
- Packing an app
|
|
25
|
+
- SwitchScripter and Switch version compatibility
|
|
26
|
+
- App Store submission guidelines
|
|
27
|
+
- Execution modes
|
|
28
|
+
<!-- docs-index:contents end -->
|
|
29
|
+
|
|
16
30
|
## Script folder files
|
|
17
31
|
|
|
18
32
|
| File | Required | Notes |
|
|
@@ -80,78 +94,8 @@ my-collection/ the folder the user works in; AI agent config and docs liv
|
|
|
80
94
|
|
|
81
95
|
## Node.js version per Switch version
|
|
82
96
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
| Switch version | `SwitchVersion` | Node.js used |
|
|
87
|
-
|---|---|---|
|
|
88
|
-
| Switch 2020 Spring | `20.0` | 12 |
|
|
89
|
-
| Switch 2020 Fall | `20.1` | 12 |
|
|
90
|
-
| Switch 2021 Spring | `21.0` | 14 |
|
|
91
|
-
| Switch 2021 Fall | `21.1` | 16 |
|
|
92
|
-
| Switch 2022 Spring | `22.0` | 16 |
|
|
93
|
-
| Switch 2022 Fall | `22.1` | 16 |
|
|
94
|
-
| Switch 2023 Fall | `23.1` | 18 |
|
|
95
|
-
| Switch 2024 Spring | `24.0` | 18 |
|
|
96
|
-
| Switch 2024 Fall | `24.1` | 20 |
|
|
97
|
-
| Switch 25.07 | `25.07` | 20 |
|
|
98
|
-
| Switch 25.11 | `25.11` | 20 |
|
|
99
|
-
| Switch 26.03 | `26.03` | 24 |
|
|
100
|
-
| Switch 26.07 | `26.07` | 24 |
|
|
101
|
-
|
|
102
|
-
Switch 26.07 bundles Node.js 12.22.12, 14.21.3, 16.20.2, 18.20.8, 20.20.0, and 24.13.0.
|
|
103
|
-
|
|
104
|
-
`SwitchVersion` controls the Node.js version only. Which scripting API methods exist depends on the
|
|
105
|
-
Switch version the script runs on, see [api-versions.md](../switch-api/api-versions.md).
|
|
106
|
-
|
|
107
|
-
### What writes `SwitchVersion`
|
|
108
|
-
|
|
109
|
-
`SwitchVersion` is the version of whichever tool last wrote the manifest. It is not a setting the
|
|
110
|
-
author picks:
|
|
111
|
-
|
|
112
|
-
- `SwitchScriptTool --create` writes the tool's own version into the new script folder.
|
|
113
|
-
- `SwitchScriptTool --pack` writes the tool's own version into the packed `.sscript`, whatever the
|
|
114
|
-
script folder's manifest says. The script folder's manifest itself is left unchanged. Verified
|
|
115
|
-
with SwitchScriptTool 26.07: a folder whose manifest said `21.0` packed to a `.sscript` whose
|
|
116
|
-
manifest says `26.07`, which moves the script from Node.js 16 to Node.js 24.
|
|
117
|
-
- SwitchScripter writes its own version on every save. Opening a script with a different
|
|
118
|
-
`SwitchVersion` shows a warning that saving updates the script to the current Node.js version.
|
|
119
|
-
|
|
120
|
-
**Gotcha:** a script folder tested directly in Switch and the `.sscript` packed from it can run on
|
|
121
|
-
different Node.js versions. A folder created with an older SwitchScriptTool keeps that tool's
|
|
122
|
-
version, but packing it with a newer SwitchScriptTool stamps the newer one. Test the packed
|
|
123
|
-
`.sscript`, not only the folder, before shipping it.
|
|
124
|
-
|
|
125
|
-
To target an older Node.js version, build the package with the SwitchScriptTool or SwitchScripter
|
|
126
|
-
of that Switch release. Editing `SwitchVersion` by hand doesn't last, because `--pack` and
|
|
127
|
-
SwitchScripter overwrite it.
|
|
128
|
-
|
|
129
|
-
### Values missing from the table
|
|
130
|
-
|
|
131
|
-
Behavior of the Switch 26.07 Server:
|
|
132
|
-
|
|
133
|
-
- No `SwitchVersion` element: treated as `20.1`, so Node.js 12.
|
|
134
|
-
- Lower than the first entry: Node.js 12.
|
|
135
|
-
- Higher than the last entry, for example a package built by a newer tool than the Switch it runs
|
|
136
|
-
on: the newest Node.js that Switch bundles. The Server logs a debug message that the script
|
|
137
|
-
"might not be compatible with the current Switch version" and runs it anyway.
|
|
138
|
-
- **Known issue:** a value that isn't an exact entry but falls numerically between the first and
|
|
139
|
-
last entries matches no Node.js version, for example `25.7` instead of `25.07`, `24.10` instead of
|
|
140
|
-
`24.1`, or `23.0`. The Server then fails to build the path to a Node.js binary, so no executor
|
|
141
|
-
process starts for the script. This was confirmed by running the Switch 26.07 lookup code with
|
|
142
|
-
these values, not by running such a script in Switch, so the exact symptom in Switch hasn't been
|
|
143
|
-
checked. A value such as `26.3` works today only because it's higher than the last entry, and it
|
|
144
|
-
will break once a later release adds an entry above it. Never hand-edit `SwitchVersion`. If you
|
|
145
|
-
must, copy a value exactly as the table above spells it.
|
|
146
|
-
|
|
147
|
-
### Other effects of `SwitchVersion`
|
|
148
|
-
|
|
149
|
-
- npm dependencies that are ES modules are bundled with esbuild before execution only when
|
|
150
|
-
`SwitchVersion` is `24.0` or higher.
|
|
151
|
-
- A script expression has no manifest. It always runs on the newest Node.js the running Switch
|
|
152
|
-
bundles.
|
|
153
|
-
|
|
154
|
-
> **Mac (Apple Silicon):** For scripts whose `SwitchVersion` is `21.1` (Switch 2021 Fall) or later, Switch runs the native ARM build of Node.js on Apple Silicon. Scripts with an earlier `SwitchVersion` run under Rosetta, because the bundled Node.js 12 and 14 are Intel-only builds. If a script bundles platform-specific binaries, ship both Intel and ARM variants.
|
|
97
|
+
`SwitchVersion` in `manifest.xml` selects the Node.js version the script runs on, and SwitchScriptTool
|
|
98
|
+
and SwitchScripter overwrite it. See [node-versions.md](node-versions.md).
|
|
155
99
|
|
|
156
100
|
## Script vs App
|
|
157
101
|
|
|
@@ -186,14 +130,14 @@ joined up explicitly:
|
|
|
186
130
|
An app loads in the Switch version it was built with **or newer**, never older. So the SwitchScripter
|
|
187
131
|
used must be at or below the oldest Switch version you intend to support, and portable
|
|
188
132
|
SwitchScripters exist for older releases specifically to build backwards-compatible apps. There is
|
|
189
|
-
no SwitchScripter for Switch 25.
|
|
133
|
+
no SwitchScripter for Switch 25.11 — use the Switch 2024 Fall SwitchScripter for it.
|
|
190
134
|
Apps as a concept require Switch 13.1 or later.
|
|
191
135
|
|
|
192
136
|
The SwitchScripter version also fixes the app's Node.js version, see
|
|
193
|
-
[
|
|
137
|
+
[node-versions.md](node-versions.md). An app built with the
|
|
194
138
|
Switch 2024 Fall SwitchScripter has `SwitchVersion` `24.1`, so it runs on Node.js 20 in every Switch
|
|
195
|
-
version that loads it, including 26.x. Switch 26.
|
|
196
|
-
it runs on Node.js 24, and it loads only in Switch 26.
|
|
139
|
+
version that loads it, including 26.x. Switch 26.11 ships SwitchScripter 26.11. An app built with
|
|
140
|
+
it runs on Node.js 24, and it loads only in Switch 26.11 or newer.
|
|
197
141
|
|
|
198
142
|
An unsigned app loads only in Switch on the machine that created it. That's what allows local
|
|
199
143
|
testing before submission; it loads elsewhere only once Enfocus has signed it.
|
|
@@ -9,6 +9,16 @@ triggers:
|
|
|
9
9
|
|
|
10
10
|
# Script Folders, Packages & SwitchScriptTool
|
|
11
11
|
|
|
12
|
+
<!-- docs-index:contents begin -->
|
|
13
|
+
## Contents
|
|
14
|
+
|
|
15
|
+
- Script folder vs script package
|
|
16
|
+
- SwitchScriptTool
|
|
17
|
+
- Commands
|
|
18
|
+
- Verify entry points before packing
|
|
19
|
+
- Deployment
|
|
20
|
+
<!-- docs-index:contents end -->
|
|
21
|
+
|
|
12
22
|
## Script folder vs script package
|
|
13
23
|
|
|
14
24
|
| | Script folder | Script package (`.sscript`) |
|
|
@@ -49,9 +59,9 @@ location for the current OS if the bare command isn't found.
|
|
|
49
59
|
|
|
50
60
|
**Pack** transpiles `main.ts` fresh into the package on every run; it never reads or modifies any `main.js` already sitting in the source folder (a stale hand-edited `main.js` there is ignored and left untouched).
|
|
51
61
|
|
|
52
|
-
Pack copies an allowlist of files, not the whole folder. Only these end up in the `.sscript`: `manifest.xml`, the declaration file named in `ScriptDeclarationFile`, the program file named in `ScriptProgramFiles` plus the `main.js` and `main.js.map` pack transpiles from it, the icon named in `ScriptIconFile`, `tsconfig.json`, the placeholder `<ScriptID>.sscript`, `Resources/`, and `node_modules/`. Everything else in the folder is left out and printed in an "Info: ... will not be packed" list, even without `--verbose`. That includes `package.json`, `package-lock.json`, `.vscode/`, a README, other `.ts`/`.js` files, subfolders other than `Resources/` and `node_modules/`, and AI agent config and docs folders. `--verbose` additionally prints the full list of what *will* be packed. Translation files were not part of this test. Verified with SwitchScriptTool
|
|
62
|
+
Pack copies an allowlist of files, not the whole folder. Only these end up in the `.sscript`: `manifest.xml`, the declaration file named in `ScriptDeclarationFile`, the program file named in `ScriptProgramFiles` plus the `main.js` and `main.js.map` pack transpiles from it, the icon named in `ScriptIconFile`, `tsconfig.json`, the placeholder `<ScriptID>.sscript`, `Resources/`, and `node_modules/`. Everything else in the folder is left out and printed in an "Info: ... will not be packed" list, even without `--verbose`. That includes `package.json`, `package-lock.json`, `.vscode/`, a README, other `.ts`/`.js` files, subfolders other than `Resources/` and `node_modules/`, and AI agent config and docs folders. `--verbose` additionally prints the full list of what *will* be packed. Translation files were not part of this test. Verified with a pre-release SwitchScriptTool build.
|
|
53
63
|
|
|
54
|
-
`node_modules` is packed as-is, so run `npm prune --production` first (see Deployment) — otherwise `devDependencies` (including `@types/*` packages, which the scaffolded `package.json` puts there) get bundled into the package for no runtime benefit. One harmless quirk: the placeholder `<ScriptID>.sscript` file scaffolded by `--create` is on the allowlist and ends up packed inside the real `.sscript` too. Pack also replaces `SwitchVersion` in the packed `manifest.xml` with SwitchScriptTool's own version (`--create` writes it too), and that value picks the Node.js version the package runs on. See [
|
|
64
|
+
`node_modules` is packed as-is, so run `npm prune --production` first (see Deployment) — otherwise `devDependencies` (including `@types/*` packages, which the scaffolded `package.json` puts there) get bundled into the package for no runtime benefit. One harmless quirk: the placeholder `<ScriptID>.sscript` file scaffolded by `--create` is on the allowlist and ends up packed inside the real `.sscript` too. Pack also replaces `SwitchVersion` in the packed `manifest.xml` with SwitchScriptTool's own version (`--create` writes it too), and that value picks the Node.js version the package runs on. See [node-versions.md § What writes `SwitchVersion`](node-versions.md#what-writes-switchversion).
|
|
55
65
|
|
|
56
66
|
**Gotcha: local modules break pack.** A `main.ts` that imports a local module (`import { x } from './helper'` or `'./lib/helper'`) fails to pack with TypeScript error TS2307 (`Cannot find module`), and no `.sscript` is written. Pack's own output shows why: `helper.ts` and `lib/helper.ts` appear in its "will not be packed" list, and the TS2307 error points at pack's temporary copy of the folder, which doesn't contain them. A `main.js` that `require`s a local file was not tested, but that file isn't packed either. The manifest also accepts only one `ScriptProgramFile` (pack errors with `The manifest must contain only one script program file`), so listing the helper there doesn't work. The verified option is to keep script code in the single program file. Shared code in an npm package under `node_modules/` might work, since `node_modules/` is packed, but that was not tested, and neither was a `file:` dependency, which npm installs as a symlink.
|
|
57
67
|
|
|
@@ -24,13 +24,13 @@ Enables autocomplete and type checking for `Switch`, `Job`, `FlowElement` and al
|
|
|
24
24
|
> `SwitchScriptTool --create` sets this up automatically for new TypeScript script folders.
|
|
25
25
|
|
|
26
26
|
v24.1.1-final is the last published version and matches the API of every Switch release from 24.1
|
|
27
|
-
to 26.
|
|
27
|
+
to 26.11. It declares every method without marking which Switch release added it, so the compiler
|
|
28
28
|
won't flag a call that an older target Switch lacks. Check those against
|
|
29
29
|
[api-versions.md](../switch-api/api-versions.md).
|
|
30
30
|
|
|
31
|
-
SwitchScriptTool 26.
|
|
31
|
+
SwitchScriptTool 26.11 also scaffolds `@types/node` 24.x whatever Node.js version the script will
|
|
32
32
|
run on. When the package will run on an older Node.js (see
|
|
33
|
-
[
|
|
33
|
+
[node-versions.md](node-versions.md)),
|
|
34
34
|
pin `@types/node` to that major version so the compiler flags newer Node.js APIs.
|
|
35
35
|
|
|
36
36
|
## TypeScript 6 / VS Code 1.114+
|
package/docs/switch-scripting.md
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
# Switch Scripting (Node.js)
|
|
2
2
|
Enfocus Switch workflow automation scripts written in TypeScript/Node.js.
|
|
3
3
|
|
|
4
|
+
Read the matching file from the API reference table below before answering any question about Switch scripting, not only before writing code. This applies to short and yes/no questions too. This page only summarises; the answer usually depends on a detail that is only in the linked file, and Switch often differs from what general Node.js or scripting knowledge suggests.
|
|
5
|
+
|
|
4
6
|
## Execution environment
|
|
5
7
|
- Entry points are top-level `async` functions with specific names — **not exported** — executed in a `node:vm.Script()` context.
|
|
6
8
|
- ESM is supported: if ES modules are present the script is bundled with ESBuild before running (when `SwitchVersion` in `manifest.xml` is `24.0` or higher).
|
|
7
9
|
- Type declarations are in `node_modules/@types/switch-scripting/index.d.ts` and must be followed precisely. They list every method up to Switch 24.1 without saying which release added it.
|
|
8
|
-
- The Node.js version comes from `SwitchVersion` in `manifest.xml`; the available API methods come from the Switch version the script runs on. See `switch-project/
|
|
10
|
+
- The Node.js version comes from `SwitchVersion` in `manifest.xml`; the available API methods come from the Switch version the script runs on. See `switch-project/node-versions.md` and `switch-api/api-versions.md`.
|
|
9
11
|
|
|
10
12
|
## API reference
|
|
11
13
|
Detailed docs live in three folders, alongside this file: `switch-api/` (the scripting API itself),
|
|
@@ -15,7 +17,7 @@ publishing guidance).
|
|
|
15
17
|
<!-- docs-index:table begin -->
|
|
16
18
|
| File | Contents | Load when |
|
|
17
19
|
|---|---|---|
|
|
18
|
-
| `switch-project/project-planning.md` |
|
|
20
|
+
| `switch-project/project-planning.md` | Planning checklist, run before scaffolding or on a project that is already scaffolded: Script vs App, job-processing approach, one script folder or several, target OS, Switch version baseline, concurrency, native/binary npm dependencies, Appstore competition risk | Starting a new script or app, before scaffolding any files, or working in a script folder that is already scaffolded where Script vs App has not been settled |
|
|
19
21
|
| `switch-api/entry-points.md` | All entry point signatures, constraints, and when each is called | Scaffolding a script, adding/editing an entry point, or making any edit to main.ts/main.js |
|
|
20
22
|
| `switch-api/switch.md` | `Switch` (`s`): global data, webhooks, abort, server utilities | Using global data, webhooks, abort, or server settings |
|
|
21
23
|
| `switch-api/flow-element.md` | `FlowElement`: properties, connections, job creation, logging | Reading properties, creating jobs, logging, connections |
|
|
@@ -24,7 +26,7 @@ publishing guidance).
|
|
|
24
26
|
| `switch-api/http.md` | `HttpRequest` / `HttpResponse` + webhook pattern | Handling incoming HTTP webhooks |
|
|
25
27
|
| `switch-api/enums.md` | All enums with string values (`LogLevel`, `AccessLevel`, `DatasetModel`, `Scope`, `Priority`, `Connection.Level`, etc.) | Looking up enum values |
|
|
26
28
|
| `switch-api/document-classes.md` | `PdfDocument`, `PdfPage`, `ImageDocument`, `XmlDocument`, `XmpDocument`: read-only file introspection | Inspecting PDF, image, XML, or XMP file contents |
|
|
27
|
-
| `switch-project/script-structure.md` | What files a script folder contains, laying out several script folders side by side, `manifest.xml` format,
|
|
29
|
+
| `switch-project/script-structure.md` | What files a script folder contains, laying out several script folders side by side, `manifest.xml` format, Script vs App, packing an app with SwitchScripter | Setting up a new script project or converting a Script to an App |
|
|
28
30
|
| `switch-project/tooling.md` | SwitchScriptTool commands and install paths, folder vs `.sscript` trade-offs, deployment | Running SwitchScriptTool: transpiling, packing, unpacking, or deploying |
|
|
29
31
|
| `switch-project/debugging.md` | Enabling debug mode in Switch Designer, debuggable entry points, VS Code attach | Debugging a script |
|
|
30
32
|
| `switch-project/vscode.md` | Type declarations, tsconfig for TypeScript 6, ESLint rules | Setting up VS Code or fixing type errors |
|
|
@@ -40,11 +42,12 @@ publishing guidance).
|
|
|
40
42
|
| `switch-appstore/app-manual.md` | Writing guidance for the separate app manual document uploaded during Appstore review (`documentation-app_name.docx` template) | Preparing the app manual document for Appstore submission |
|
|
41
43
|
| `switch-appstore/app-store-submission.md` | Writing guidance for the Create Appstore App / Create Appstore App Version web forms: Short Description, What's new, Eula, icon specs, and which fields reuse content already written elsewhere | Preparing content for the Appstore website submission forms |
|
|
42
44
|
| `switch-api/api-versions.md` | Which Switch release added each scripting API class, method, and enum value; API availability follows the running Switch, not `manifest.xml` | Writing or reviewing code for a script or app that must run on a Switch version older than the latest, or when the user names a minimum Switch version |
|
|
45
|
+
| `switch-project/node-versions.md` | How `SwitchVersion` in `manifest.xml` selects the Node.js version, the version table per Switch release, which tools overwrite `SwitchVersion`, values missing from the table, other effects of `SwitchVersion` | Working out which Node.js version a script or app will run on, or what `SwitchVersion` in manifest.xml does |
|
|
43
46
|
<!-- docs-index:table end -->
|
|
44
47
|
|
|
45
48
|
## Key rules
|
|
46
49
|
- Before scaffolding a new script or app, work through `switch-project/project-planning.md` with the user.
|
|
47
|
-
|
|
50
|
+
If the script folder is already scaffolded, still ask Script or App; the manifest cannot answer it.
|
|
48
51
|
- If the script or app must run on a Switch version older than the latest, check each API call
|
|
49
52
|
against `switch-api/api-versions.md`. The API files mark anything newer than the baseline with
|
|
50
53
|
"Switch X+" (a `// Switch X+` comment above a signature, or a note in the text), meaning that
|