@enfocussw/switch-scripting-context 25.11.0-beta.12 → 25.11.0-beta.13

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 CHANGED
@@ -5,6 +5,69 @@ All notable changes to this package are documented here. Format follows
5
5
 
6
6
  ## [Unreleased]
7
7
 
8
+ ## [25.11.0-beta.13] - 2026-09-09
9
+
10
+ ### Fixed
11
+ - README's two CHANGELOG links pointed at an unversioned jsdelivr URL, which always serves the
12
+ *latest published* file. On GitHub that showed the published file rather than the repo's live one,
13
+ hiding unreleased entries. Both are now relative links, so GitHub resolves them to the live file.
14
+ - Generated tool config (Cursor, Codex/OpenCode, Windsurf, Zed, Cline) — the "Core rules" block told
15
+ agents never to edit `<ScriptID>.xml` and to send the user to SwitchScripter instead. That has
16
+ contradicted `api-script-declaration.md` and the `switch-scripting.md` key rules since the agent
17
+ editing policy was added, and it sat in an always-on rules file that outranks any doc the agent
18
+ loads later. Now matches the docs: direct editing is fine under the declaration's rules.
19
+
20
+ ### Added
21
+ - `api-switch.md` — a "Translation extraction rules" section under `Switch.tr()`. Extraction is
22
+ static source analysis, so aliasing `Switch.tr`, concatenating with a variable, or interpolating
23
+ a template literal silently produces no translation entry at all. Documents what does work
24
+ (all quote styles, multi-line, literal-only concatenation, marking a string away from its use
25
+ site) and the `%1` + `messageParams` pattern for dynamic values.
26
+ - `api-job-patterns.md` — "Driving a third-party CLI application", the Node.js replacement for the
27
+ legacy `findApplicationPath`/`ApplicationPath` mechanism: a custom path property on the
28
+ `automatic;choosefile;sltextwithvar;scriptexp` chain, resolved once in `flowStartTriggered` into
29
+ `Scope.FlowElement` global data, with `failProcess()` when discovery fails and cleanup in
30
+ `flowStopTriggered`.
31
+ - `api-script-structure.md` — "Packing an app" and SwitchScripter/Switch version compatibility:
32
+ script folders can only be typed `Script` (pack, then retype to `App` in SwitchScripter), extra
33
+ files are unavailable in script-folder mode, the pack ID is always `com.enfocus.*` and is carried
34
+ over by opening the previous `.enfpack`, an app loads only in its build version or newer (no
35
+ Scripter for 25.07/25.11 — use 2024 Fall), and an unsigned app loads only on the machine that
36
+ built it.
37
+ - `api-app-guidelines.md` — the App-only section is now split into Identity and versioning,
38
+ Top-level declaration properties, Password protection, Localization, Icon, Extra files, Source
39
+ and review hygiene, and what review does and doesn't cover. New rules from the App SDK: script ID
40
+ charset and uniqueness, resubmit-without-bumping after a rejection, minor-version format, the
41
+ three-category limit and Product Management approval, unsigned apps always loading under
42
+ "Custom", `DetailedInfo` feeding the generated HTML docs, `ExecutionGroup` coordination for a
43
+ shared third-party application, `Compatibility`/`SupportInfo`/`AppDiscovery` being required to
44
+ build the pack at all, Node.js password protection being unrecoverable, the six-language limit on
45
+ app translations, the 200×200 Appstore icon, and macOS notarization checks via `codesign -dv`.
46
+ - Generated tool config and `switch-scripting.md` key rules — added the entry-point scanner
47
+ constraints (literal `function` keyword; no trailing-backslash string literals, regex literals, or
48
+ non-`word / word` division) to the always-on rules. Previously these lived only in
49
+ `api-entry-points.md`, so an agent making a small edit without opening that file had no signal
50
+ that the failure mode exists, and it fails silently.
51
+
52
+ ### Changed
53
+ - Generated tool config for Cursor, Codex/OpenCode, Windsurf, Zed and Cline now lists each API doc
54
+ with its "Load when" routing text instead of a bare filename, so those agents can open the one
55
+ file they need without reading `switch-scripting.md` first. Costs ~600 tokens in the always-on
56
+ block, saves a ~1,300-token hub read per session.
57
+ - The routing table in `docs/switch-scripting.md` is now the single source for that list. `init.ts`
58
+ parses it (`parseRoutingTable()`); the two hardcoded 19-entry arrays are gone, as is the drift
59
+ they invited.
60
+ - `api-script-structure.md` — moved "App Store submission guidelines" into
61
+ `api-app-guidelines.md` § App-only and "Execution modes" into `api-execution-environment.md`,
62
+ leaving pointers at both old headings. Reviewing an app or reasoning about concurrency previously
63
+ needed two files for one topic. Existing anchor links still resolve.
64
+ - `docs/switch-scripting.md` and `README.md` — sharpened the routing descriptions for
65
+ `api-job.md` (signatures) vs `api-job-patterns.md` (rules and gotchas), and for
66
+ `api-script-structure.md` vs `api-tooling.md`. Their triggers overlapped enough that an agent had
67
+ to load both files for any job-handling task.
68
+ - `init` no longer copies `docs/superpowers`, `docs/temp`, or `.DS_Store` into a consuming project.
69
+ The published tarball already excludes them, but `init` run from a git clone did not.
70
+
8
71
  ## [25.11.0-beta.12] - 2026-09-08
9
72
 
10
73
  ### Fixed
package/README.md CHANGED
@@ -4,7 +4,7 @@ AI coding assistant context for [Enfocus Switch](https://www.enfocus.com/en/swit
4
4
 
5
5
  Installs curated API reference docs and generates config files for 8 AI coding agents (Claude Code, GitHub Copilot, Cursor, Codex CLI/OpenCode, Gemini CLI, Windsurf, Zed, and Cline) 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/CHANGELOG.md) (also included in this package) for what's changed between versions.
7
+ See [CHANGELOG.md](CHANGELOG.md) (also included in this package) for what's changed between versions.
8
8
 
9
9
  ## Usage
10
10
 
@@ -84,7 +84,7 @@ A few things this gets you without asking for them by name:
84
84
  properties (app path/license) are off-limits and left to SwitchScripter's GUI instead.
85
85
 
86
86
  Re-run `init` after upgrading this package so the copied docs and generated config files catch up —
87
- see [CHANGELOG.md](https://cdn.jsdelivr.net/npm/@enfocussw/switch-scripting-context/CHANGELOG.md) for what changed.
87
+ see [CHANGELOG.md](CHANGELOG.md) for what changed.
88
88
 
89
89
  ## Options
90
90
 
@@ -132,7 +132,7 @@ The `switch-docs/` folder contains:
132
132
 
133
133
  - `switch-scripting.md` — master index with execution environment rules and "load when" routing table
134
134
  - `switch-api/api-entry-points.md` — all entry point signatures and when each is called
135
- - `switch-api/api-job.md` — `Job` class: routing, file access, child jobs, private data, datasets
135
+ - `switch-api/api-job.md` — `Job` class signatures: routing, file access, child jobs, private data, datasets
136
136
  - `switch-api/api-flow-element.md` — `FlowElement`: properties, connections, job creation, logging
137
137
  - `switch-api/api-switch.md` — `Switch` global: global data, webhooks, abort, server utilities
138
138
  - `switch-api/api-connection.md` — `Connection`: type, properties, file count
@@ -140,13 +140,13 @@ The `switch-docs/` folder contains:
140
140
  - `switch-api/api-enums.md` — all enums with string values (`LogLevel`, `AccessLevel`, `Scope`, etc.)
141
141
  - `switch-api/api-document-classes.md` — `PdfDocument`, `ImageDocument`, `XmlDocument`, `XmpDocument`
142
142
  - `switch-api/api-script-declaration.md` — XML declaration reference
143
- - `switch-api/api-script-structure.md` — script folder/package structure and manifest format
143
+ - `switch-api/api-script-structure.md` — script folder contents, manifest format, Node.js version per Switch release, Script vs App
144
144
  - `switch-api/api-tooling.md` — SwitchScriptTool commands, script folder vs package, build and deployment
145
145
  - `switch-api/api-debugging.md` — enabling debug mode, debuggable entry points, VS Code attach
146
146
  - `switch-api/api-logging.md` — log levels, when/what to log, `console.log` limitation, common gotchas
147
147
  - `switch-api/api-logs-and-dataroot.md` — locating the application data root, querying `ServerLogs.db3` directly to diagnose a script
148
148
  - `switch-api/api-vscode.md` — type declarations, tsconfig for TypeScript 6, ESLint rules
149
149
  - `switch-api/api-property-editors.md` — property editor types and string return values
150
- - `switch-api/api-job-patterns.md` — file access semantics, routing rules, child jobs, executor limits
151
- - `switch-api/api-execution-environment.md` — process model, state persistence across jobs, error handling, npm/native module constraints
152
- - `switch-api/api-app-guidelines.md` — pre-publish checklist for Appstore apps: property naming/tooltips/editors, entry point and sendTo consistency, logging quality, packaging
150
+ - `switch-api/api-job-patterns.md` — `Job` rules and gotchas: file access semantics, temp cleanup, routing rules, child jobs, executor limits
151
+ - `switch-api/api-execution-environment.md` — execution modes, process model, state persistence across jobs, error handling, npm/native module constraints
152
+ - `switch-api/api-app-guidelines.md` — pre-publish checklist for Appstore apps: property naming/tooltips/editors, entry point and sendTo consistency, logging quality, packaging, app-only submission rules
package/dist/init.d.ts CHANGED
@@ -9,6 +9,21 @@ export interface ToolDefinition {
9
9
  altIds?: string[];
10
10
  files: ToolFile[];
11
11
  }
12
+ export interface ApiDoc {
13
+ /** Filename within docs/switch-api/, e.g. "api-job.md". */
14
+ file: string;
15
+ /** The routing table's "Load when" text, verbatim. */
16
+ loadWhen: string;
17
+ }
18
+ /**
19
+ * The routing table in docs/switch-scripting.md is the single source of truth for
20
+ * which API docs exist and when to load each one. Everything the CLI generates is
21
+ * derived from it, so a new doc file needs registering in exactly one place here
22
+ * (plus README.md, which init.test.ts checks).
23
+ */
24
+ export declare function parseRoutingTable(root?: string): ApiDoc[];
25
+ /** Filenames only, in routing-table order. */
26
+ export declare function apiFiles(root?: string): string[];
12
27
  export declare function generateAgentsMd(docsDir: string): string;
13
28
  export declare function generateGeminiMd(docsDir: string): string;
14
29
  export declare function generateWindsurfRules(docsDir: string): string;
package/dist/init.js CHANGED
@@ -33,6 +33,8 @@ var __importStar = (this && this.__importStar) || (function () {
33
33
  };
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.parseRoutingTable = parseRoutingTable;
37
+ exports.apiFiles = apiFiles;
36
38
  exports.generateAgentsMd = generateAgentsMd;
37
39
  exports.generateGeminiMd = generateGeminiMd;
38
40
  exports.generateWindsurfRules = generateWindsurfRules;
@@ -47,6 +49,46 @@ const readline = __importStar(require("readline"));
47
49
  // ─── Markers ─────────────────────────────────────────────────────────────────
48
50
  const MARKER_BEGIN = '<!-- switch-scripting-context begin -->';
49
51
  const MARKER_END = '<!-- switch-scripting-context end -->';
52
+ // ─── Shared content (single source of truth for all generated tool files) ────
53
+ /** Package root, whether running from src/ (ts-node) or dist/. */
54
+ function packageRoot() {
55
+ return path.resolve(__dirname, '..');
56
+ }
57
+ /**
58
+ * The routing table in docs/switch-scripting.md is the single source of truth for
59
+ * which API docs exist and when to load each one. Everything the CLI generates is
60
+ * derived from it, so a new doc file needs registering in exactly one place here
61
+ * (plus README.md, which init.test.ts checks).
62
+ */
63
+ function parseRoutingTable(root = packageRoot()) {
64
+ const hub = fs.readFileSync(path.join(root, 'docs', 'switch-scripting.md'), 'utf8');
65
+ const docs = [];
66
+ for (const line of hub.split('\n')) {
67
+ // | `switch-api/<file>.md` | <contents> | <load when> |
68
+ const m = /^\|\s*`switch-api\/(api-[a-z0-9-]+\.md)`\s*\|(.*)\|(.*)\|\s*$/.exec(line);
69
+ if (m)
70
+ docs.push({ file: m[1], loadWhen: m[3].trim() });
71
+ }
72
+ if (docs.length === 0) {
73
+ throw new Error('No API docs found in docs/switch-scripting.md — the routing table format changed. ' +
74
+ 'Generated tool config would be empty; fix parseRoutingTable() before publishing.');
75
+ }
76
+ return docs;
77
+ }
78
+ /** Filenames only, in routing-table order. */
79
+ function apiFiles(root) {
80
+ return parseRoutingTable(root).map(d => d.file);
81
+ }
82
+ const INLINE_CORE_RULES = `## Core rules
83
+
84
+ - Entry point functions are top-level async functions — do NOT use \`export\`, arrow functions, or class methods; declare them with the literal \`function\` keyword.
85
+ - 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 \`api-entry-points.md\` § Entry-point scanner constraints before editing \`main.ts\`/\`main.js\`.
86
+ - Every \`jobArrived\` must end with exactly one \`job.sendTo*()\` or \`job.fail()\`.
87
+ - Use \`AccessLevel.ReadOnly\` for \`job.get()\` unless the file content will be modified.
88
+ - After \`createJob()\`, \`createChild()\`, or \`createDataset()\` with a file path, delete the source file after routing — Switch does not auto-remove it.
89
+ - The XML declaration (\`<ScriptID>.xml\`) can be edited directly — read \`api-script-declaration.md\` first and follow its rules exactly (nothing validates this format, so mistakes fail silently). Never change an existing script's \`Name\`; bump \`Version\` on every declaration edit. Leave \`manifest.xml\` to the user unless explicitly asked.
90
+ - After editing \`main.ts\`, transpile with \`SwitchScriptTool --transpile <folder>\` — do not use \`tsc\` directly.
91
+ - Never use a script folder in production — pack with \`SwitchScriptTool --pack\` first; folders are excluded from flow exports.`;
50
92
  // ─── Content generators ──────────────────────────────────────────────────────
51
93
  function generateClaudeMd(docsDir) {
52
94
  return `${MARKER_BEGIN}
@@ -76,28 +118,6 @@ You are working on an Enfocus Switch scripting project (Node.js/TypeScript).
76
118
  ${MARKER_END}`;
77
119
  }
78
120
  function generateCursorMdc(docsDir) {
79
- const apiFiles = [
80
- 'api-entry-points.md',
81
- 'api-job.md',
82
- 'api-flow-element.md',
83
- 'api-connection.md',
84
- 'api-http.md',
85
- 'api-enums.md',
86
- 'api-document-classes.md',
87
- 'api-script-declaration.md',
88
- 'api-script-structure.md',
89
- 'api-tooling.md',
90
- 'api-debugging.md',
91
- 'api-vscode.md',
92
- 'api-property-editors.md',
93
- 'api-job-patterns.md',
94
- 'api-switch.md',
95
- 'api-execution-environment.md',
96
- 'api-logging.md',
97
- 'api-logs-and-dataroot.md',
98
- 'api-app-guidelines.md',
99
- ];
100
- const fileList = apiFiles.map(f => `- \`${docsDir}/switch-api/${f}\``).join('\n');
101
121
  return `---
102
122
  description: Enfocus Switch scripting rules and API reference for Node.js/TypeScript scripts
103
123
  globs: ["**/*.ts", "**/*.js"]
@@ -107,56 +127,21 @@ alwaysApply: false
107
127
  ${MARKER_BEGIN}
108
128
  You are working on an Enfocus Switch scripting project (Node.js/TypeScript).
109
129
 
110
- ## Core rules
111
-
112
- - Entry point functions are top-level async functions — do NOT use \`export\`.
113
- - Every \`jobArrived\` must end with exactly one \`job.sendTo*()\` or \`job.fail()\`.
114
- - Use \`AccessLevel.ReadOnly\` for \`job.get()\` unless the file content will be modified.
115
- - After \`createJob()\`, \`createChild()\`, or \`createDataset()\` with a file path, delete the source file after routing — Switch does not auto-remove it.
116
- - Never edit \`<ScriptID>.xml\` or \`manifest.xml\` directly. For property/connection changes, instruct the user to use SwitchScripter.
117
- - After editing \`main.ts\`, transpile with \`SwitchScriptTool --transpile <folder>\` — do not use \`tsc\` directly.
118
- - Never use a script folder in production — pack with \`SwitchScriptTool --pack\` first; folders are excluded from flow exports.
130
+ ${INLINE_CORE_RULES}
119
131
 
120
132
  ## API reference
121
133
 
122
- Read \`${docsDir}/switch-scripting.md\` for the full index, then consult the relevant file:
134
+ Load the file matching the task below. \`${docsDir}/switch-scripting.md\` has the same index plus
135
+ the project-wide key rules:
123
136
 
124
- ${fileList}
137
+ ${inlineApiFileList(docsDir)}
125
138
  ${MARKER_END}`;
126
139
  }
127
- // ─── Shared inline content (for tools without @file import support) ──────────
128
- const INLINE_CORE_RULES = `## Core rules
129
-
130
- - Entry point functions are top-level async functions — do NOT use \`export\`.
131
- - Every \`jobArrived\` must end with exactly one \`job.sendTo*()\` or \`job.fail()\`.
132
- - Use \`AccessLevel.ReadOnly\` for \`job.get()\` unless the file content will be modified.
133
- - After \`createJob()\`, \`createChild()\`, or \`createDataset()\` with a file path, delete the source file after routing — Switch does not auto-remove it.
134
- - Never edit \`<ScriptID>.xml\` or \`manifest.xml\` directly. For property/connection changes, instruct the user to use SwitchScripter.
135
- - After editing \`main.ts\`, transpile with \`SwitchScriptTool --transpile <folder>\` — do not use \`tsc\` directly.
136
- - Never use a script folder in production — pack with \`SwitchScriptTool --pack\` first; folders are excluded from flow exports.`;
137
- const API_FILES = [
138
- 'api-entry-points.md',
139
- 'api-job.md',
140
- 'api-flow-element.md',
141
- 'api-connection.md',
142
- 'api-http.md',
143
- 'api-enums.md',
144
- 'api-document-classes.md',
145
- 'api-script-declaration.md',
146
- 'api-script-structure.md',
147
- 'api-tooling.md',
148
- 'api-debugging.md',
149
- 'api-vscode.md',
150
- 'api-property-editors.md',
151
- 'api-job-patterns.md',
152
- 'api-switch.md',
153
- 'api-execution-environment.md',
154
- 'api-logging.md',
155
- 'api-logs-and-dataroot.md',
156
- 'api-app-guidelines.md',
157
- ];
140
+ // ─── Inline block (for tools without @file import support) ──────────────────
158
141
  function inlineApiFileList(docsDir) {
159
- return API_FILES.map(f => `- \`${docsDir}/switch-api/${f}\``).join('\n');
142
+ return parseRoutingTable()
143
+ .map(d => `- \`${docsDir}/switch-api/${d.file}\` — ${d.loadWhen}`)
144
+ .join('\n');
160
145
  }
161
146
  function generateInlineBlock(docsDir) {
162
147
  return `You are working on an Enfocus Switch scripting project (Node.js/TypeScript).
@@ -165,7 +150,8 @@ ${INLINE_CORE_RULES}
165
150
 
166
151
  ## API reference
167
152
 
168
- Read \`${docsDir}/switch-scripting.md\` for the full index, then consult the relevant file:
153
+ Load the file matching the task below. \`${docsDir}/switch-scripting.md\` has the same index plus
154
+ the project-wide key rules:
169
155
 
170
156
  ${inlineApiFileList(docsDir)}`;
171
157
  }
@@ -347,13 +333,25 @@ function applyFileAction(action, dryRun) {
347
333
  console.log(` ${rel} → ${label}`);
348
334
  }
349
335
  // ─── Docs copy ────────────────────────────────────────────────────────────────
336
+ /** Paths under docs/ that are never shipped to a consuming project. */
337
+ const DOCS_EXCLUDE = ['superpowers', 'temp'];
350
338
  function copyDocs(packageRoot, destDir, dryRun) {
351
339
  const src = path.join(packageRoot, 'docs');
352
340
  if (dryRun) {
353
341
  console.log(` [dry-run] Copying docs/ → ${path.relative(process.cwd(), destDir)}/`);
354
342
  return;
355
343
  }
356
- fs.cpSync(src, destDir, { recursive: true });
344
+ // The published tarball already omits these, but init may run from a git clone.
345
+ fs.cpSync(src, destDir, {
346
+ recursive: true,
347
+ filter: (from) => {
348
+ const rel = path.relative(src, from);
349
+ if (!rel)
350
+ return true;
351
+ const [top] = rel.split(path.sep);
352
+ return !DOCS_EXCLUDE.includes(top) && path.basename(from) !== '.DS_Store';
353
+ },
354
+ });
357
355
  console.log(` docs → ${path.relative(process.cwd(), destDir)}/`);
358
356
  }
359
357
  // ─── .gitignore update ───────────────────────────────────────────────────────
@@ -3,7 +3,8 @@
3
3
  A pre-publish checklist for a script intended for the Enfocus Appstore (`ScriptPackageType="App"`
4
4
  — see [api-script-structure.md § Script vs App](api-script-structure.md#script-vs-app)). Each item
5
5
  here is enforced in more detail at the linked section — this page exists to be read top-to-bottom
6
- right before submission, not as the primary source for any individual rule.
6
+ right before submission, not as the primary source for any individual rule. The one exception is
7
+ [App-only](#app-only) at the bottom, which is documented in full here.
7
8
 
8
9
  Items fall into three tiers, marked on each one:
9
10
 
@@ -108,15 +109,133 @@ detail.
108
109
 
109
110
  ## App-only
110
111
 
111
- The following apply only to `ScriptPackageType="App"`, not to a plain `Script` package at all. See
112
- [api-script-structure.md § App Store submission guidelines](api-script-structure.md#app-store-submission-guidelines)
113
- for full detail.
114
-
115
- - [ ] The app is preferably available in more languages than just English.
116
- - [ ] Where translations are used, they're complete (every shipped language has every string), and
117
- logging goes through the translation mechanism rather than hardcoded English.
118
- - [ ] Any macOS Mach-O binaries (executables or dynamic libraries) in extra files are built for
119
- both `x86_64` and `arm64`.
120
- - [ ] Any macOS Mach-O binaries in extra files are signed.
121
- - [ ] No file that might be modified or regenerated at runtime is placed inside the app's own
122
- package folder that would fail the app's signature validation and cause Switch to remove it.
112
+ The following apply only to `ScriptPackageType="App"`, not to a plain `Script` package at all.
113
+ Unlike the sections above, these are documented in full here rather than deferring elsewhere.
114
+
115
+ ### Identity and versioning
116
+
117
+ - [ ] **`Name` (Script ID) matches `[A-Za-z0-9_-]+`** letters, digits, hyphens and underscores
118
+ only, no spaces. It must also be globally unique across the Appstore; Enfocus checks for clashes
119
+ at review and may require a change. Pick something unlikely to collide.
120
+ - [ ] **`Name` never changes across versions.** It is what identifies the app in an existing
121
+ customer flow, so changing it breaks the upgrade path. `DisplayName` *can* change freely between
122
+ versions without breaking upgrades so keep any third-party application version number out of
123
+ `Name`, and preferably out of `DisplayName` too, or every application release forces a rename.
124
+ - [ ] **`Version` is only incremented once the previous version was actually published.** If a
125
+ submission is rejected, resubmit under the *same* version number rather than bumping. Minor
126
+ versions are allowed to one level (`1.1`, `1.10`, `1.34`); leading zeros are not (`1.01` is
127
+ invalid).
128
+ - [ ] **Every app in an app bundle carries the same version**, including the master app entry.
129
+ - [ ] **The pack ID always starts with `com.enfocus.`**, generated from the script ID, regardless
130
+ of the company name and domain set in SwitchScripter preferences. To keep it stable when
131
+ updating, open the existing `.enfpack` (not the `.sscript`) before re-packing — SwitchScripter
132
+ remembers the pack ID from the pack it opened.
133
+
134
+ ### Top-level declaration properties
135
+
136
+ - [ ] **App-level `Tooltip` is filled in** — this is the tooltip on the icon in the Elements pane,
137
+ separate from the per-property tooltips above.
138
+ - [ ] **`Keywords` is populated and matches the keywords on the app's Appstore detail page.** Words
139
+ already in `DisplayName` are implicitly searchable and don't need repeating. Matching is
140
+ case-insensitive.
141
+ - [ ] **`ExecutionMode="Concurrent"` wherever the script allows it.** `Serialized` is the default
142
+ and the slower choice; concurrent is preferred for throughput. If you go concurrent, the script
143
+ must synchronise its own access to any shared resource — see
144
+ [api-execution-environment.md § Execution modes](api-execution-environment.md#execution-modes).
145
+ - [ ] **`ExecutionGroup` is shared across every app that drives the same non-concurrent third-party
146
+ application**, so Switch can stop them using it simultaneously. If your app is in that situation,
147
+ ask Enfocus which group name to use rather than inventing one.
148
+ - [ ] **`PerformanceTuning="Yes"` only with a concrete reason.** It exposes `IdleAfterJob` (and
149
+ `NumberOfSlots`) to the user; don't surface those knobs by default.
150
+ - [ ] **At most three categories, and `SubcategoryInElementPane` is filled in.** New categories need
151
+ Enfocus Product Management approval, and an app listed in more than three needs additional
152
+ approval. Note that an unsigned app always loads under the **Custom** subcategory regardless of
153
+ what it declares — the declared subcategory only takes effect once Enfocus has signed the app, and
154
+ review may change it.
155
+ - [ ] **`DetailedInfo` is present on every property and every connection**, not just `Tooltip`.
156
+ Switch Designer generates the app's HTML documentation from these, so an empty `DetailedInfo`
157
+ produces a blank entry in the shipped docs.
158
+ - [ ] **`Description`, `Compatibility`, `SupportInfo` and `AppDiscovery` are filled in.** These are
159
+ required to create the `.enfpack` at all, and `SupportInfo` must point at *your* support channel,
160
+ never Enfocus Support.
161
+ - [ ] **The declared incoming/outgoing connection topology matches what the code actually does** —
162
+ see [Entry points](#entry-points) and [Sending jobs](#sending-jobs) above.
163
+ - [ ] **Dependent properties have real dependency conditions and values, never left empty**, and the
164
+ script does not read a dependent property's value when its master isn't set to the value that
165
+ makes it relevant.
166
+
167
+ ### Password protection
168
+
169
+ - [ ] **The app is password protected with a non-trivial password** (8+ characters, mixed case,
170
+ digits, symbols). Enfocus checks the password strength at review.
171
+ - [ ] **Don't lose the password.** For a Node.js app, Switch runs an obfuscated copy of the code
172
+ produced at save time and never needs the original source, so the protection is genuinely
173
+ one-way: Enfocus cannot recover a Node.js script's source if the author forgets the password.
174
+ (For legacy JavaScript/VBScript a bypass mechanism exists internally at Enfocus, so that
175
+ protection is weaker — another reason to be on Node.js.)
176
+ - [ ] Note that a published Node.js app ships only the obfuscated code, re-protected with a random
177
+ password Enfocus generates during review — not the password you set.
178
+
179
+ ### Localization
180
+
181
+ - [ ] **Prefer more than one language.** An app is preferably localized beyond English — see
182
+ [Translation files](api-script-structure.md#script-folder-files) (`<LanguageCode>.ts`) and
183
+ `SwitchScriptTool --generate-translations` in [api-tooling.md](api-tooling.md).
184
+ - [ ] **The app's own translations are limited to the six Switch UI languages** (English, French,
185
+ German, Italian, Chinese, Japanese); other languages are not accepted for the app itself. The
186
+ separate Appstore *documentation* may be supplied in additional languages, since it isn't
187
+ generated through the SDK.
188
+ - [ ] **Translations must be complete, and logging must go through the translation mechanism.** A
189
+ partially-translated app (some strings translated, others not) is not acceptable — every
190
+ user-facing message needs an entry in each shipped language file, and log calls must go through
191
+ that mechanism rather than hardcoding English text that bypasses it. Note that
192
+ `Switch.tr()` extraction is static and silently skips anything that isn't a plain string literal
193
+ — see [api-switch.md § Translation extraction rules](api-switch.md#translation-extraction-rules).
194
+ Check the generated `.ts` files rather than assuming.
195
+
196
+ ### Icon
197
+
198
+ - [ ] **32×32 PNG, RGB, transparent background**, attached as the app icon. This is what appears in
199
+ the Elements pane and in flows.
200
+ - [ ] **A separate 200×200 version is supplied to Enfocus** for the Appstore listing — it is not
201
+ part of the pack.
202
+
203
+ ### Extra files
204
+
205
+ - [ ] **macOS Mach-O binaries in extra files (`Resources/`) must be universal.** Any bundled macOS
206
+ application, framework bundle, executable, or dynamic library must include both `x86_64` and
207
+ `arm64` architectures. Relying on Rosetta 2 costs performance and isn't a long-term option.
208
+ - [ ] **macOS Mach-O binaries in extra files must be signed and notarized.** An unsigned or
209
+ incorrectly signed executable or dynamic library will fail Appstore review. At minimum, sign with
210
+ hardened runtime enabled and a secure timestamp; verify with `codesign -dv <file>` and check the
211
+ output contains a `Timestamp` line and the `runtime` flag on the `CodeDirectory` line.
212
+ - [ ] **Extra files must not change at runtime.** Don't place files the script might modify or
213
+ regenerate at runtime — license files included — inside the app's own package folder. Switch
214
+ validates the app package's signature, and content that changes after signing fails that
215
+ validation, causing Switch to remove the app. Write runtime-mutable data (temp files, caches,
216
+ generated output) outside the app folder — see
217
+ [api-job-patterns.md § Temp file cleanup](api-job-patterns.md#temp-file-cleanup).
218
+ - [ ] Find bundled files at runtime with `flowElement.getPluginResourcesPath()` — see
219
+ [api-flow-element.md](api-flow-element.md).
220
+
221
+ ### Source and review hygiene
222
+
223
+ - [ ] **Comments in the source are in English**, so Enfocus reviewers can read them.
224
+ - [ ] **No malicious or unrelated payload** — nothing that harms the user's machine or installs
225
+ additional software.
226
+ - [ ] **No Oracle JRE embedded**, in a script or an app, for licensing reasons — see
227
+ [api-script-structure.md § Script folder files](api-script-structure.md#script-folder-files).
228
+ - [ ] **Automating a third-party application doesn't breach that application's licence.** Some
229
+ vendors' terms explicitly exclude automation; check before building.
230
+
231
+ ### What review does and doesn't cover
232
+
233
+ Enfocus verifies that the app loads correctly and becomes available as a flow element, and checks
234
+ the items above. It does **not** test that the app works — functional correctness, error handling,
235
+ code structure and naming are the app creator's responsibility, though good practice in all of them
236
+ is assumed. Items marked as rejection-triggers in the SDK's own checklist are the identity,
237
+ password, icon, signing and architecture ones above.
238
+
239
+ Budget roughly **10 business days** for a review. An unsigned app only loads in Switch on the
240
+ machine that created it, which is what makes local testing possible before submission; once signed
241
+ it loads anywhere. Apps require Switch 13.1 or later.
@@ -1,13 +1,29 @@
1
1
  # Execution Environment
2
2
 
3
- How the Node.js process a script runs in behaves, beyond the entry point API itself. These are
4
- consequences of the host process model, not things a script configures — understanding them avoids
5
- subtle bugs around state persistence and error handling.
3
+ How the Node.js process a script runs in behaves, beyond the entry point API itself. Apart from the
4
+ execution mode below, these are consequences of the host process model rather than things a script
5
+ configures — understanding them avoids subtle bugs around state persistence and error handling.
6
+
7
+ ## Execution modes
8
+
9
+ Set in the XML declaration via SwitchScripter, or by editing it directly (see
10
+ [api-script-declaration.md](api-script-declaration.md#built-in-elementfields)). Applies to all
11
+ instances of the script.
12
+
13
+ **Concurrent** — entry points for the same or different instances may run in parallel. Scripts must
14
+ synchronize access to any shared resources. `NumberOfSlots` is only meaningful in this mode.
15
+
16
+ **Serialized** — entry points within the same **execution group** are never concurrent. Instances
17
+ in different execution groups may still run in parallel.
18
+
19
+ **Execution group** — only relevant for Serialized mode. Should be a reverse-domain string (e.g.
20
+ `com.mycompany.myScript`) to avoid collisions. Defaults to the Script ID if left empty.
21
+
22
+ Neither setting maps to a count of Node.js OS processes — see below.
6
23
 
7
24
  ## Two independent concurrency tiers
8
25
 
9
- `NumberOfSlots`/`ExecutionGroup` (see
10
- [Execution modes](api-script-structure.md#execution-modes)) and the pool of Node.js processes that
26
+ `NumberOfSlots`/`ExecutionGroup` (above) and the pool of Node.js processes that
11
27
  actually run script code are governed completely separately — there is no one-to-one mapping between
12
28
  them:
13
29
 
@@ -132,3 +132,32 @@ The Node.js executor process is recycled when any of the following thresholds is
132
132
  On cleanup, any files/folders created in the temp area are removed. Always close file handles and database connections before the entry point returns.
133
133
 
134
134
  See [api-execution-environment.md](api-execution-environment.md) for how this process model affects state persistence and error handling across job invocations.
135
+
136
+ ## Driving a third-party CLI application
137
+
138
+ `findApplicationPath` and the `ApplicationPath` property are the legacy-scripting mechanism for
139
+ locating a third-party application; neither is available to Node.js scripts, and `ApplicationPath`
140
+ is a reserved name Switch silently drops from the declaration (see
141
+ [api-script-declaration.md](api-script-declaration.md#built-in-elementfields)). A Node.js script or
142
+ app that shells out to an external binary resolves the path itself, using the following pattern.
143
+
144
+ 1. Declare an ordinary custom property for the path under a name of your own — `cliPath`, not
145
+ `ApplicationPath`.
146
+ 2. Give it the editor chain `automatic;choosefile;sltextwithvar;scriptexp`, with
147
+ `Default="Automatic"` and `Subtype="automatic"`. The `automatic` literal editor is what lets the
148
+ user express "find it yourself" without typing a magic string, and `getPropertyStringValue()`
149
+ returns the literal `"Automatic"` for it — see
150
+ [api-property-editors.md § Literal editors](api-property-editors.md#literal-editors).
151
+ 3. Resolve the path once per flow start, in `flowStartTriggered`: if the property reads
152
+ `Automatic`, run whatever discovery the application needs; otherwise take
153
+ `flowElement.getPropertyStringValue('cliPath')`. Verify the resulting path actually exists, then
154
+ store it in global data at `Scope.FlowElement`. If it doesn't exist, store an empty string
155
+ rather than leaving the tag unset.
156
+ 4. In `jobArrived`/`timerFired`, read the path back from global data. An empty string means
157
+ discovery failed: call `flowElement.failProcess()` so the element goes into an error state,
158
+ instead of failing every individual job.
159
+ 5. Remove the global data entry in `flowStopTriggered` — global data is never cleaned up
160
+ automatically (see [api-switch.md § Global data](api-switch.md#global-data)).
161
+
162
+ Doing discovery once at flow start rather than per job keeps a filesystem search off the job path,
163
+ and gives the operator a single clear element-level error when the application is missing.
@@ -72,39 +72,46 @@ A Switch script project lives in a **script folder** during development and is d
72
72
  | Distribution | Freely | Enfocus Appstore only |
73
73
  | Position in pane | — | Configured via `PositionInElementPane` in XML |
74
74
 
75
+ ## Packing an app
76
+
77
+ An app is produced by SwitchScripter, not by SwitchScriptTool, and the two workflows have to be
78
+ joined up explicitly:
79
+
80
+ - **A script folder can only be typed `Script`.** To ship one as an app, pack it with
81
+ `SwitchScriptTool --pack` first, then open the resulting package in SwitchScripter and change the
82
+ type to `App` before creating the `.enfpack`. If "Create pack" is greyed out, the type is still
83
+ `Script`.
84
+ - **Extra files can't be managed while SwitchScripter is working with a script folder.** Convert to
85
+ a script package first. The conversion is reversible, so the `.pdesc` holding the extra-files
86
+ configuration can be round-tripped back into the script folder and kept in version control.
87
+ - **Creating a pack does not save the script.** Save first, or the pack is built from the last
88
+ saved state.
89
+ - **The pack ID is derived from the script ID and always starts with `com.enfocus.`**, whatever the
90
+ company name and domain in SwitchScripter preferences. To keep it stable across an update, open
91
+ the previous `.enfpack` rather than the `.sscript` — SwitchScripter carries the pack ID over from
92
+ the pack it opened, even if the script ID or domain has since changed.
93
+
94
+ ### SwitchScripter and Switch version compatibility
95
+
96
+ An app loads in the Switch version it was built with **or newer**, never older. So the SwitchScripter
97
+ used must be at or below the oldest Switch version you intend to support, and portable
98
+ SwitchScripters exist for older releases specifically to build backwards-compatible apps. There is
99
+ no SwitchScripter for Switch 25.07 or 25.11 — use the Switch 2024 Fall SwitchScripter for those.
100
+ Apps as a concept require Switch 13.1 or later.
101
+
102
+ An unsigned app loads only in Switch on the machine that created it. That's what allows local
103
+ testing before submission; it loads elsewhere only once Enfocus has signed it.
104
+
75
105
  ## App Store submission guidelines
76
106
 
77
- The following apply **only** to `ScriptPackageType="App"` (Appstore submission) not to a plain
78
- `Script` package beyond the general property/entry-point/logging conventions covered elsewhere in
79
- these docs:
80
-
81
- - **Prefer more than one language.** An app is preferably localized beyond English — see
82
- [Translation files](#script-folder-files) (`<LanguageCode>.ts`) and
83
- `SwitchScriptTool --generate-translations` in [api-tooling.md](api-tooling.md).
84
- - **Translations must be complete, and logging must go through the translation mechanism.** A
85
- partially-translated app (some strings translated, others not) is not acceptable — every
86
- user-facing message needs an entry in each shipped language file, and log calls must go through
87
- that mechanism (see [api-switch.md](api-switch.md) for `Switch.translate`) rather than
88
- hardcoding English text that bypasses it.
89
- - **macOS Mach-O binaries in extra files (`Resources/`) must be universal.** Any bundled macOS
90
- application, framework bundle, executable, or dynamic library must include both `x86_64` and
91
- `arm64` architectures.
92
- - **macOS Mach-O binaries in extra files must be signed.** An unsigned executable or dynamic
93
- library bundled as an extra file will fail Appstore review.
94
- - **Extra files must not change at runtime.** Don't place files the script might modify or
95
- regenerate at runtime inside the app's own package folder — Switch validates the app package's
96
- signature, and content that changes after signing fails that validation, causing Switch to remove
97
- the app. Write runtime-mutable data (temp files, caches, generated output) outside the app
98
- folder — see [api-job-patterns.md § Temp file cleanup](api-job-patterns.md#temp-file-cleanup).
107
+ App-specific submission rules (localization, universal/signed macOS binaries, immutable extra
108
+ files) live in [api-app-guidelines.md § App-only](api-app-guidelines.md#app-only), alongside the
109
+ rest of the pre-publish checklist.
99
110
 
100
111
  ## Execution modes
101
112
 
102
- Set in the XML declaration via SwitchScripter. Applies to all instances of the script.
103
-
104
- **Concurrent** entry points for the same or different instances may run in parallel. Scripts must synchronize access to any shared resources.
105
-
106
- **Serialized** entry points within the same **execution group** are never concurrent. Instances in different execution groups may still run in parallel.
107
-
108
- **Execution group** — only relevant for Serialized mode. Should be a reverse-domain string (e.g. `com.mycompany.myScript`) to avoid collisions. Defaults to the Script ID if left empty.
109
-
110
- See [api-execution-environment.md](api-execution-environment.md#two-independent-concurrency-tiers) — neither `NumberOfSlots` nor execution group maps to a count of Node.js OS processes; they gate job dispatch on the Switch Server, separate from the pooled executor processes that actually run script code.
113
+ `Concurrent`/`Serialized`, `ExecutionGroup` and `NumberOfSlots` are set in the XML declaration (see
114
+ [api-script-declaration.md](api-script-declaration.md#built-in-elementfields) for the attributes)
115
+ and documented in
116
+ [api-execution-environment.md § Execution modes](api-execution-environment.md#execution-modes),
117
+ which also explains why none of them maps to a count of Node.js processes.
@@ -73,3 +73,52 @@ Returns the Switch server version as `majorVersion + updateNumber/100` (e.g. Swi
73
73
  Switch.tr(str: string): string
74
74
  ```
75
75
  Static method. Marks a string literal for translation (used by SwitchScriptTool). Returns the string unchanged at runtime.
76
+
77
+ ### Translation extraction rules
78
+
79
+ `SwitchScriptTool --generate-translations` extracts strings by **static analysis of the source
80
+ text**, not by running it. It only ever sees a `Switch.tr(...)` call whose argument is a string
81
+ literal, spelled exactly like that. Anything it can't resolve statically is silently skipped — no
82
+ error, no warning, just a missing entry in the `.ts` file. Always check the generated `.ts` for the
83
+ strings you expected.
84
+
85
+ What extraction handles:
86
+
87
+ ```ts
88
+ Switch.tr('single'); // single, double and backtick quotes all work
89
+ Switch.tr(`multi
90
+ line`); // multi-line literals work
91
+ Switch.tr('one ' + 'two '); // concatenation of literals works
92
+ // The tr() call doesn't have to sit at the point of use:
93
+ const s = Switch.tr('Predefined string');
94
+ await job.log(LogLevel.Info, s); // extracted, and translated at runtime
95
+ ```
96
+
97
+ What it does **not** handle:
98
+
99
+ ```ts
100
+ const t = Switch.tr; // aliasing the function: never extracted
101
+ await job.log(LogLevel.Info, t('nope'));
102
+
103
+ const token = getToken();
104
+ Switch.tr('prefix ' + token); // concatenation with a non-literal
105
+ Switch.tr(`prefix ${token}`); // template interpolation
106
+ Switch.tr('Job ID = ' + job.getId());
107
+ ```
108
+
109
+ For dynamic values, mark the template and pass the values as `messageParams` — the template gets
110
+ translated, the substituted values don't:
111
+
112
+ ```ts
113
+ await job.log(LogLevel.Info, Switch.tr('Job ID = %1'), [job.getId()]);
114
+ ```
115
+
116
+ Arguments can themselves be translated by wrapping them separately:
117
+
118
+ ```ts
119
+ const mode = readOnly ? Switch.tr('Read-only') : Switch.tr('Regular');
120
+ await job.log(LogLevel.Info, Switch.tr('Job ID = %1, Mode = %2'), [job.getId(), mode]);
121
+ ```
122
+
123
+ See [api-logging.md § Placeholders instead of concatenation](api-logging.md#placeholders-instead-of-concatenation)
124
+ for the same rule stated from the logging side.
@@ -14,26 +14,32 @@ Detailed API docs are in `docs/switch-api/`:
14
14
  | `switch-api/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 |
15
15
  | `switch-api/api-switch.md` | `Switch` (`s`) — global data, webhooks, abort, server utilities | Using global data, webhooks, abort, or server settings |
16
16
  | `switch-api/api-flow-element.md` | `FlowElement` — properties, connections, job creation, logging | Reading properties, creating jobs, logging, connections |
17
- | `switch-api/api-job.md` | `Job` routing, file access, child jobs, private data, datasets | Processing/routing jobs, file access, private data, datasets |
17
+ | `switch-api/api-job.md` | `Job` **signatures**: routing, file access, child jobs, private data, datasets | Looking up what a `job.*` method takes, returns, or throws |
18
18
  | `switch-api/api-connection.md` | `Connection` — type, properties, file count | Routing to specific connections or reading connection properties |
19
19
  | `switch-api/api-http.md` | `HttpRequest` / `HttpResponse` + webhook pattern | Handling incoming HTTP webhooks |
20
20
  | `switch-api/api-enums.md` | All enums with string values (`LogLevel`, `AccessLevel`, `DatasetModel`, `Scope`, `Priority`, `Connection.Level`, etc.) | Looking up enum values |
21
21
  | `switch-api/api-document-classes.md` | `PdfDocument`, `PdfPage`, `ImageDocument`, `XmlDocument`, `XmpDocument` — read-only file introspection | Inspecting PDF, image, XML, or XMP file contents |
22
- | `switch-api/api-script-structure.md` | Script folder/package files, manifest format, App vs Script, execution modes | Setting up a new script project or converting to an App |
23
- | `switch-api/api-tooling.md` | SwitchScriptTool commands, script folder vs package, build and deployment | Creating, building, packaging, or deploying a script |
22
+ | `switch-api/api-script-structure.md` | What files a script folder contains, `manifest.xml` format, Node.js version per Switch release, Script vs App | Setting up a new script project, or converting a Script to an App |
23
+ | `switch-api/api-tooling.md` | SwitchScriptTool commands and install paths, folder vs `.sscript` trade-offs, deployment | Running SwitchScriptTool: transpiling, packing, unpacking, or deploying |
24
24
  | `switch-api/api-debugging.md` | Enabling debug mode in Switch Designer, debuggable entry points, VS Code attach | Debugging a script |
25
25
  | `switch-api/api-vscode.md` | Type declarations, tsconfig for TypeScript 6, ESLint rules | Setting up VS Code or fixing type errors |
26
26
  | `switch-api/api-script-declaration.md` | XML declaration reference: properties, connections, execution config — agents may edit this file directly | Understanding, adding, or editing script properties/connections/execution config |
27
27
  | `switch-api/api-property-editors.md` | Property editor types, string return values, literal editors, dropdowns | Defining property editors in XML or reading property values in code |
28
- | `switch-api/api-job-patterns.md` | File access semantics, temp cleanup, routing rules, child jobs, executor limits | Processing jobs, creating child jobs, working with datasets, routing to multiple connections |
29
- | `switch-api/api-execution-environment.md` | Process/concurrency model, state persistence across job invocations, unhandled-rejection behavior, npm/native module constraints | Relying on module-level state across jobs, handling errors/rejections, or using third-party npm packages |
28
+ | `switch-api/api-job-patterns.md` | `Job` **rules and gotchas**: file access semantics, temp cleanup, which `sendTo*()` suits which connection type, dataset/child ordering, executor limits | Writing or reviewing job-handling code. Pair with `api-job.md` when you also need signatures |
29
+ | `switch-api/api-execution-environment.md` | Execution modes (`Concurrent`/`Serialized`, `ExecutionGroup`, `NumberOfSlots`), process/concurrency model, state persistence across job invocations, unhandled-rejection behavior, npm/native module constraints | Choosing or changing an execution mode, relying on module-level state across jobs, handling errors/rejections, or using third-party npm packages |
30
30
  | `switch-api/api-logging.md` | Log level semantics, logging practice, `console.log` limitation, common gotchas | Adding or reviewing `job.log()`/`flowElement.log()`/`job.fail()`/`failProcess()` calls |
31
31
  | `switch-api/api-logs-and-dataroot.md` | Locating the Application Data Root, querying `ServerLogs.db3` directly | Diagnosing or validating a script from its actual log output rather than by reading the code |
32
- | `switch-api/api-app-guidelines.md` | Pre-publish checklist for Appstore apps: property naming/tooltips/editors, entry point and sendTo consistency, logging quality, packaging | Preparing a script for publication as an app, or reviewing one against Appstore submission criteria |
32
+ | `switch-api/api-app-guidelines.md` | Pre-publish checklist for Appstore apps: property naming/tooltips/editors, entry point and sendTo consistency, logging quality, packaging, and the app-only submission rules (localization, signed universal macOS binaries) | Preparing a script for publication as an app, or reviewing one against Appstore submission criteria |
33
33
 
34
34
  ## Key rules
35
35
  - Always consult the API reference files above before writing or modifying script code.
36
- - Do not `export` entry point functions.
36
+ - Do not `export` entry point functions. Declare them with the literal `function` keyword at top
37
+ level — arrow functions, `exports.name = ...`, and class methods are invisible to Switch.
38
+ - Switch discovers entry points with a regex, not a parser. Never write a string literal whose
39
+ content ends with a backslash, a regex literal, or division outside the plain `word / word`
40
+ shape — each silently deletes a span of real code, and every entry point inside that span
41
+ disappears with no error anywhere. Read `switch-api/api-entry-points.md` §
42
+ Entry-point scanner constraints before editing `main.ts`/`main.js`.
37
43
  - Every `jobArrived` invocation must end with exactly one `job.sendTo*()` or `job.fail()` call — either in the same invocation or deferred to `timerFired` via job information stored in global data.
38
44
  - Use `AccessLevel.ReadOnly` for `job.get()` unless the file content will be modified.
39
45
  - Use VS Code snippets (`.vscode/switch.code-snippets`, prefix `switch…`) to scaffold entry points.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@enfocussw/switch-scripting-context",
3
- "version": "25.11.0-beta.12",
3
+ "version": "25.11.0-beta.13",
4
4
  "description": "AI coding assistant context for Enfocus Switch scripting (Node.js/TypeScript)",
5
5
  "keywords": [
6
6
  "switch",