unity-open-mcp 0.4.0 → 0.5.0

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.
Files changed (40) hide show
  1. package/README.md +10 -7
  2. package/dist/capabilities/build-capabilities.js +6 -0
  3. package/dist/capabilities/build-capabilities.js.map +1 -1
  4. package/dist/capabilities/cost-hints.js +10 -0
  5. package/dist/capabilities/cost-hints.js.map +1 -1
  6. package/dist/capabilities/lifecycle.js +13 -0
  7. package/dist/capabilities/lifecycle.js.map +1 -1
  8. package/dist/capabilities/tool-groups.js +4 -0
  9. package/dist/capabilities/tool-groups.js.map +1 -1
  10. package/dist/cli/ping-poller.js +20 -0
  11. package/dist/cli/ping-poller.js.map +1 -1
  12. package/dist/dialog-dismiss.js +82 -6
  13. package/dist/dialog-dismiss.js.map +1 -1
  14. package/dist/dialog-policy.js +4 -0
  15. package/dist/dialog-policy.js.map +1 -1
  16. package/dist/live-client.d.ts +23 -0
  17. package/dist/live-client.js +95 -0
  18. package/dist/live-client.js.map +1 -1
  19. package/dist/running-unity.d.ts +105 -0
  20. package/dist/running-unity.js +387 -0
  21. package/dist/running-unity.js.map +1 -0
  22. package/dist/skill/client-paths.d.ts +22 -0
  23. package/dist/skill/client-paths.js +66 -5
  24. package/dist/skill/client-paths.js.map +1 -1
  25. package/dist/skill/generate-skill.d.ts +43 -4
  26. package/dist/skill/generate-skill.js +132 -34
  27. package/dist/skill/generate-skill.js.map +1 -1
  28. package/dist/tool-router.js +40 -0
  29. package/dist/tool-router.js.map +1 -1
  30. package/dist/tools/batch-execute.d.ts +2 -0
  31. package/dist/tools/batch-execute.js +83 -0
  32. package/dist/tools/batch-execute.js.map +1 -0
  33. package/dist/tools/bridge-status.js +8 -1
  34. package/dist/tools/bridge-status.js.map +1 -1
  35. package/dist/tools/generate-skill.js +8 -0
  36. package/dist/tools/generate-skill.js.map +1 -1
  37. package/dist/tools/index.d.ts +1 -0
  38. package/dist/tools/index.js +10 -0
  39. package/dist/tools/index.js.map +1 -1
  40. package/package.json +1 -1
@@ -0,0 +1,387 @@
1
+ // M27 Plan 1 — Cold Safe Mode / dead-bridge detection (process-presence scan).
2
+ //
3
+ // When Unity launches directly into Safe Mode (the bridge assembly fails to
4
+ // compile from a cold start), the bridge's `[InitializeOnLoad]` static
5
+ // constructor never runs, so **no instance lock is ever written**.
6
+ // `classifyInstance(null)` returns `gone` — the same classification as "Unity
7
+ // is not running." Without a positive signal, the MCP server cannot tell the
8
+ // agent to call `read_compile_errors`; it must guess or follow the SKILL's
9
+ // manual `ps`/`grep` workaround.
10
+ //
11
+ // This module ports the Hub's Unity-process scanner
12
+ // (`hub/src-tauri/src/config/running_unity.rs`) into the MCP server so the
13
+ // cold-start case can be detected: when `classifyInstance` is `gone` AND a
14
+ // live Unity process whose command line references this project is found,
15
+ // callers (`bridge_status`, `LiveClient`, the CLI `wait-for-ready`) treat the
16
+ // state as **cold Safe Mode / bridge never compiled** and surface the same
17
+ // recovery path as mid-session `dead_bridge` → `read_compile_errors`.
18
+ //
19
+ // The MCP helper only needs **single-project lookup** (does any Unity process
20
+ // match THIS project path?), not the Hub's full multi-project scan, so the
21
+ // public surface is just `findUnityForProject(projectPath)`.
22
+ //
23
+ // Cross-platform: macOS + Windows (match the Hub). Linux returns null — the
24
+ // Hub also returns an empty list on every other target, so this is no
25
+ // regression. No new runtime deps: `node:child_process`, `node:path`, and the
26
+ // shared `normalizePath` from `instance-discovery.ts` (NOT the Hub's
27
+ // `canonicalize` — case-sensitive paths on macOS/Linux must compare verbatim,
28
+ // and canonicalize would normalize away the very differences that distinguish
29
+ // two projects).
30
+ import { execFileSync } from "node:child_process";
31
+ import { normalizePath } from "./instance-discovery.js";
32
+ /**
33
+ * Pure `-projectPath` argument parser. Port of Hub
34
+ * `running_unity.rs#parse_project_path_arg`. Accepts both the space-separated
35
+ * (`-projectPath <value>`) and equals (`-projectPath=<value>`) forms, plus
36
+ * the long `--projectPath` variants. Surrounding single or double quotes on
37
+ * the value are stripped. Returns the first match (matching the rest of the
38
+ * Hub CLI surface); null when the flag is absent or sits at the end of argv
39
+ * with no value.
40
+ *
41
+ * This is the unit-testable core: the OS-specific scanners feed it an argv
42
+ * slice extracted from `ps` / PowerShell output.
43
+ */
44
+ export function parseProjectPathArg(args) {
45
+ for (let i = 0; i < args.length; i++) {
46
+ const arg = args[i];
47
+ const eqForm = stripPrefix(arg, "-projectPath=") ?? stripPrefix(arg, "--projectPath=");
48
+ if (eqForm !== null) {
49
+ return unquote(eqForm);
50
+ }
51
+ if (arg === "-projectPath" || arg === "--projectPath") {
52
+ const next = args[i + 1];
53
+ if (next === undefined)
54
+ return null; // flag at end with no value
55
+ return unquote(next);
56
+ }
57
+ }
58
+ return null;
59
+ }
60
+ /** Return `rest` when `value` starts with `prefix`, else null. */
61
+ function stripPrefix(value, prefix) {
62
+ if (value.startsWith(prefix))
63
+ return value.slice(prefix.length);
64
+ return null;
65
+ }
66
+ /**
67
+ * Strip a single layer of surrounding double or single quotes from a flag
68
+ * value. Hub-launched Unity passes the path unquoted on macOS (the OS handles
69
+ * spaces natively) and quoted on Windows when the path contains spaces. We
70
+ * accept both because the flag may have been supplied by a third-party tool.
71
+ */
72
+ function unquote(value) {
73
+ const trimmed = value.trim();
74
+ if (trimmed.length >= 2) {
75
+ const first = trimmed.charCodeAt(0);
76
+ const last = trimmed.charCodeAt(trimmed.length - 1);
77
+ const dq = '"'.charCodeAt(0);
78
+ const sq = "'".charCodeAt(0);
79
+ if ((first === dq && last === dq) || (first === sq && last === sq)) {
80
+ return trimmed.slice(1, -1);
81
+ }
82
+ }
83
+ return trimmed;
84
+ }
85
+ /**
86
+ * `true` when the command line's executable basename is `Unity`
87
+ * (case-sensitive — `unityhub://` URL handlers and the `Unity Hub` GUI do not
88
+ * match). Windows is filtered by the PowerShell `Name='Unity.exe'` selector
89
+ * upstream, so this helper is only used for the macOS / `ps` path.
90
+ *
91
+ * Extracting the executable path from a `ps` command line is harder than it
92
+ * looks: the Hub GUI binary lives at
93
+ * `/Applications/Unity Hub.app/Contents/MacOS/Unity Hub` — i.e. the executable
94
+ * name itself contains a space, and the parent directory contains the word
95
+ * "Unity". A naive `split_whitespace().next()` would return `/Applications/Unity`,
96
+ * which basename-matches `Unity` and (incorrectly) tags the Hub GUI as a
97
+ * running editor. We solve this by extending the executable prefix past any
98
+ * tokens that don't look like flags: the Unity editor is virtually always
99
+ * launched with `-projectPath` (or some other `-flag`), so the first `-flag`
100
+ * token is a reliable end-of-path marker.
101
+ */
102
+ export function isUnityCommandLine(commandLine) {
103
+ const executable = firstExecutablePath(commandLine);
104
+ const unquoted = trimMatching(executable, '"', "'");
105
+ const name = basenameSafe(unquoted);
106
+ return name === "Unity";
107
+ }
108
+ function trimMatching(value, ...chars) {
109
+ let s = value;
110
+ while (s.length > 0) {
111
+ const c = s[0];
112
+ if (!chars.includes(c))
113
+ break;
114
+ // Trim a matching pair only when both ends agree; otherwise stop.
115
+ if (s.length < 2 || s[s.length - 1] !== c)
116
+ break;
117
+ s = s.slice(1, -1);
118
+ }
119
+ return s;
120
+ }
121
+ function basenameSafe(path) {
122
+ if (!path)
123
+ return "";
124
+ // `path.basename` mishandles Windows-style paths on a non-Windows host;
125
+ // split on both separators and take the last non-empty segment.
126
+ const segments = path.split(/[\\/]/).filter((s) => s.length > 0);
127
+ return segments.length > 0 ? segments[segments.length - 1] : "";
128
+ }
129
+ /**
130
+ * Extract the executable path prefix from a `ps` command line. If the line
131
+ * starts with a `"`, consume the matching closing quote. Otherwise extend the
132
+ * prefix through any tokens that don't start with `-`, stopping at the first
133
+ * flag (or end of line). Port of Hub `first_executable_path`.
134
+ */
135
+ function firstExecutablePath(commandLine) {
136
+ if (commandLine.length === 0)
137
+ return commandLine;
138
+ if (commandLine[0] === '"') {
139
+ const end = commandLine.indexOf('"', 1);
140
+ if (end >= 0)
141
+ return commandLine.slice(0, end + 1);
142
+ }
143
+ let pos = 0;
144
+ for (const token of commandLine.split(/\s+/)) {
145
+ if (token.startsWith("-") && token !== "--") {
146
+ return commandLine.slice(0, pos).trimEnd();
147
+ }
148
+ // +1 for the whitespace split() consumed.
149
+ pos += token.length + 1;
150
+ }
151
+ return commandLine.trimEnd();
152
+ }
153
+ /**
154
+ * Naive argv splitter for a `ps`-formatted command line. Honours double and
155
+ * single quotes and treats backslashes as literal (macOS `ps` output never
156
+ * escapes them). Port of Hub `split_args`.
157
+ */
158
+ export function splitArgs(line) {
159
+ const out = [];
160
+ let current = "";
161
+ let inSingle = false;
162
+ let inDouble = false;
163
+ for (const ch of line) {
164
+ if (ch === "'" && !inDouble) {
165
+ inSingle = !inSingle;
166
+ continue;
167
+ }
168
+ if (ch === '"' && !inSingle) {
169
+ inDouble = !inDouble;
170
+ continue;
171
+ }
172
+ if (/\s/.test(ch) && !inSingle && !inDouble) {
173
+ if (current.length > 0) {
174
+ out.push(current);
175
+ current = "";
176
+ }
177
+ continue;
178
+ }
179
+ current += ch;
180
+ }
181
+ if (current.length > 0)
182
+ out.push(current);
183
+ return out;
184
+ }
185
+ /**
186
+ * Windows argv splitter. Same rules as {@link splitArgs} but treats `/` and
187
+ * `\` as ordinary characters (Windows paths use both). Honours `\"` as an
188
+ * embedded literal quote inside a double-quoted string, matching the
189
+ * `CommandLine` quoting convention emitted by `Get-CimInstance Win32_Process`.
190
+ * Port of Hub `split_args_windows`.
191
+ */
192
+ export function splitArgsWindows(line) {
193
+ const out = [];
194
+ let current = "";
195
+ let inDouble = false;
196
+ const chars = Array.from(line);
197
+ for (let i = 0; i < chars.length; i++) {
198
+ const ch = chars[i];
199
+ if (inDouble && ch === "\\") {
200
+ const next = chars[i + 1];
201
+ if (next === '"' || next === "\\") {
202
+ current += next;
203
+ i += 1;
204
+ continue;
205
+ }
206
+ }
207
+ if (ch === '"') {
208
+ inDouble = !inDouble;
209
+ continue;
210
+ }
211
+ if (/\s/.test(ch) && !inDouble) {
212
+ if (current.length > 0) {
213
+ out.push(current);
214
+ current = "";
215
+ }
216
+ continue;
217
+ }
218
+ current += ch;
219
+ }
220
+ if (current.length > 0)
221
+ out.push(current);
222
+ return out;
223
+ }
224
+ /**
225
+ * Parse macOS `ps -axww -o pid=,command=` output. One line per process: the
226
+ * PID is the first whitespace-delimited token, the rest is the full command.
227
+ * Lines whose executable basename is not `Unity` are skipped (rejects the Hub
228
+ * GUI, `unityhub://` URL handlers, unrelated tools). Port of Hub
229
+ * `parse_ps_output`.
230
+ */
231
+ export function parsePsOutput(stdout) {
232
+ const out = [];
233
+ for (const line of stdout.split(/\r?\n/)) {
234
+ const trimmed = line.replace(/^\s+/, "");
235
+ if (trimmed.length === 0)
236
+ continue;
237
+ const m = trimmed.match(/^(\S+)\s+(.*)$/);
238
+ if (!m)
239
+ continue;
240
+ const pidStr = m[1];
241
+ const rest = m[2].replace(/^\s+/, "");
242
+ const pid = Number.parseInt(pidStr, 10);
243
+ if (!Number.isInteger(pid) || pid <= 0)
244
+ continue;
245
+ if (!isUnityCommandLine(rest))
246
+ continue;
247
+ const projectPath = parseProjectPathArg(splitArgs(rest));
248
+ out.push({
249
+ pid,
250
+ projectPath: projectPath !== null ? normalizePath(projectPath) : null,
251
+ });
252
+ }
253
+ return out;
254
+ }
255
+ /**
256
+ * Parse the `PID|commandline` lines emitted by the PowerShell scan.
257
+ * `CommandLine` is `null` for system-owned processes; we record the PID
258
+ * without a project path so the caller can still do its PID-only fallback.
259
+ * Port of Hub `parse_powershell_lines`.
260
+ */
261
+ export function parsePowerShellLines(stdout) {
262
+ const out = [];
263
+ for (const line of stdout.split(/\r?\n/)) {
264
+ const trimmed = line.trim();
265
+ if (trimmed.length === 0)
266
+ continue;
267
+ const bar = trimmed.indexOf("|");
268
+ if (bar < 0)
269
+ continue;
270
+ const pidStr = trimmed.slice(0, bar);
271
+ const rest = trimmed.slice(bar + 1);
272
+ const pid = Number.parseInt(pidStr, 10);
273
+ if (!Number.isInteger(pid) || pid <= 0)
274
+ continue;
275
+ const projectPath = rest.length === 0 || rest === "null"
276
+ ? null
277
+ : parseProjectPathArg(splitArgsWindows(rest));
278
+ out.push({
279
+ pid,
280
+ projectPath: projectPath !== null ? normalizePath(projectPath) : null,
281
+ });
282
+ }
283
+ return out;
284
+ }
285
+ /** macOS `ps -axww -o pid=,command=` scanner. Port of Hub `scan_macos`. */
286
+ function scanMacos() {
287
+ let stdout;
288
+ try {
289
+ stdout = execFileSync("ps", ["-axww", "-o", "pid=,command="], {
290
+ encoding: "utf8",
291
+ });
292
+ }
293
+ catch {
294
+ // ps missing or failed (non-macOS CI container without procps). Return
295
+ // empty — the cold-Safe-Mode branch then falls through to "stopped", the
296
+ // pre-feature behavior, so no regression.
297
+ return [];
298
+ }
299
+ return parsePsOutput(stdout);
300
+ }
301
+ /** Windows PowerShell `Get-CimInstance Win32_Process` scanner. Port of Hub
302
+ * `scan_windows`. */
303
+ function scanWindows() {
304
+ const script = "Get-CimInstance Win32_Process -Filter \"Name='Unity.exe'\" | " +
305
+ "ForEach-Object { Write-Output ($_.ProcessId.ToString() + '|' + $_.CommandLine) }";
306
+ let stdout;
307
+ try {
308
+ stdout = execFileSync("powershell", ["-NoProfile", "-NonInteractive", "-Command", script], { encoding: "utf8", windowsHide: true });
309
+ }
310
+ catch {
311
+ // PowerShell missing or failed. Return empty.
312
+ return [];
313
+ }
314
+ return parsePowerShellLines(stdout);
315
+ }
316
+ /** Real scanner — dispatches to the OS-native command. Linux/other → empty. */
317
+ const realScanner = {
318
+ scan() {
319
+ const platform = process.platform;
320
+ if (platform === "darwin")
321
+ return scanMacos();
322
+ if (platform === "win32")
323
+ return scanWindows();
324
+ return []; // Linux + others: no regression (Hub matches).
325
+ },
326
+ };
327
+ // Mutable binding so tests can swap in a fake without threading a dependency
328
+ // through every caller. Default is the real OS scanner.
329
+ let currentScanner = realScanner;
330
+ /** Read the active scanner. Callers (`findUnityForProject`) use this. */
331
+ export function getUnityProcessScanner() {
332
+ return currentScanner;
333
+ }
334
+ /**
335
+ * Install a fake scanner for tests. Returns a restore function that re-binds
336
+ * the previous scanner (so concurrent test files don't leak state). Production
337
+ * code MUST NOT call this.
338
+ */
339
+ export function setUnityProcessScannerForTest(fake) {
340
+ const prev = currentScanner;
341
+ currentScanner = fake ?? realScanner;
342
+ return () => {
343
+ currentScanner = prev;
344
+ };
345
+ }
346
+ /**
347
+ * Scan for a live Unity process whose command line references `projectPath`.
348
+ *
349
+ * Returns `{ pid }` for the first match (by PID), or null when no Unity
350
+ * process matches. Path comparison uses {@link normalizePath} from
351
+ * `instance-discovery.ts` (case-sensitive on macOS/Linux — `canonicalize`
352
+ * would normalize away the very differences that distinguish two projects,
353
+ * and the Hub does the same on its side).
354
+ *
355
+ * Also matches when Unity is running WITHOUT `-projectPath` (bare editor
356
+ * launch). The Hub covers this via `lastLaunchPid`; the MCP server has no
357
+ * persisted launch PID, so this is a known false negative we accept — the
358
+ * scan simply returns null and the caller falls back to its pre-feature
359
+ * behavior. Documented in tests.
360
+ *
361
+ * Never throws: any scanner failure (ps missing, PowerShell slow, parse
362
+ * error) returns null. A failed scan must not mask the underlying offline
363
+ * state.
364
+ *
365
+ * @param projectPath absolute Unity project root to match against.
366
+ */
367
+ export function findUnityForProject(projectPath) {
368
+ if (!projectPath)
369
+ return null;
370
+ const target = normalizePath(projectPath);
371
+ if (target.length === 0)
372
+ return null;
373
+ let found = [];
374
+ try {
375
+ found = getUnityProcessScanner().scan();
376
+ }
377
+ catch {
378
+ return null;
379
+ }
380
+ for (const proc of found) {
381
+ if (proc.projectPath !== null && normalizePath(proc.projectPath) === target) {
382
+ return { pid: proc.pid };
383
+ }
384
+ }
385
+ return null;
386
+ }
387
+ //# sourceMappingURL=running-unity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"running-unity.js","sourceRoot":"","sources":["../src/running-unity.ts"],"names":[],"mappings":"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"}
@@ -19,6 +19,28 @@ export declare const BUNDLED_MANIFEST: ClientPathsManifest;
19
19
  * process).
20
20
  */
21
21
  export declare function loadClientPathsManifest(): ClientPathsManifest;
22
+ /**
23
+ * Absolute path to the template skill file
24
+ * (`<toolkitRoot>/<manifest.templateRelativePath>`), resolved from the
25
+ * same root discovery that loads `client-paths.json`. Returns `null`
26
+ * when the toolkit root cannot be found (bundled-fallback / standalone
27
+ * `mcp-server/` install) so callers can degrade gracefully instead of
28
+ * guessing a path. Never throws.
29
+ *
30
+ * Used by the skill generator to merge the template workflow prose
31
+ * with the project-specific inventory (the template is the source of
32
+ * truth for the workflow playbook).
33
+ */
34
+ export declare function resolveTemplateSkillPath(): string | null;
35
+ /**
36
+ * @internal Test-only cache reset. The manifest resolution is cached
37
+ * for process lifetime (it is immutable in production, where the env
38
+ * override is set before the process starts). Tests that mutate
39
+ * `UNITY_OPEN_MCP_TOOLKIT_ROOT` after a prior test already warmed the
40
+ * cache need this to observe the override. Do not call from runtime
41
+ * code.
42
+ */
43
+ export declare function _clearClientPathsCacheForTests(): void;
22
44
  /**
23
45
  * Project-relative skill path for a client key
24
46
  * (`cursor` / `claude` / `opencode` / `agents`). Throws for unknown
@@ -34,15 +34,37 @@ export const BUNDLED_MANIFEST = {
34
34
  claude: { relativePath: ".claude/skills/unity-open-mcp/SKILL.md" },
35
35
  opencode: { relativePath: ".opencode/skills/unity-open-mcp/SKILL.md" },
36
36
  agents: { relativePath: ".agents/skills/unity-open-mcp/SKILL.md" },
37
+ cline: { relativePath: ".cline/skills/unity-open-mcp/SKILL.md" },
38
+ gemini: { relativePath: ".gemini/skills/unity-open-mcp/SKILL.md" },
39
+ kilocode: { relativePath: ".kilocode/skills/unity-open-mcp/SKILL.md" },
40
+ roo: { relativePath: ".roo/skills/unity-open-mcp/SKILL.md" },
41
+ agent: { relativePath: ".agent/skills/unity-open-mcp/SKILL.md" },
42
+ junie: { relativePath: ".junie/skills/unity-open-mcp/SKILL.md" },
43
+ vscode: { relativePath: ".vscode/skills/unity-open-mcp/SKILL.md" },
44
+ vs: { relativePath: ".vs/skills/unity-open-mcp/SKILL.md" },
45
+ github: { relativePath: ".github/skills/unity-open-mcp/SKILL.md" },
37
46
  },
38
47
  mcpClientMapping: {
39
48
  cursor: ["cursor"],
49
+ "cursor-project": ["cursor"],
40
50
  "claude-desktop": ["claude"],
41
51
  "claude-code": ["claude"],
42
52
  "opencode-global": ["opencode"],
43
53
  "opencode-project": ["opencode"],
44
54
  "zcode-global": ["agents"],
45
55
  "zcode-project": ["agents"],
56
+ zoocode: ["roo"],
57
+ cline: ["cline"],
58
+ codex: ["agents"],
59
+ gemini: ["gemini"],
60
+ "github-copilot-cli": ["claude"],
61
+ "kilo-code": ["kilocode"],
62
+ rider: ["junie"],
63
+ "unity-ai": [],
64
+ "vscode-copilot": ["vscode"],
65
+ "vs-copilot": ["vs"],
66
+ antigravity: ["agent"],
67
+ custom: ["cursor", "claude", "opencode", "agents"],
46
68
  manual: ["cursor", "claude", "opencode", "agents"],
47
69
  },
48
70
  };
@@ -71,13 +93,13 @@ function tryReadManifest(path) {
71
93
  return null;
72
94
  }
73
95
  }
74
- function resolveManifest() {
96
+ function resolveManifestWithRoot() {
75
97
  // 1. Explicit env override.
76
98
  const envRoot = process.env.UNITY_OPEN_MCP_TOOLKIT_ROOT?.trim();
77
99
  if (envRoot) {
78
100
  const fromEnv = tryReadManifest(join(envRoot, MANIFEST_REL));
79
101
  if (fromEnv)
80
- return fromEnv;
102
+ return { manifest: fromEnv, toolkitRoot: envRoot };
81
103
  }
82
104
  // 2. Walk up from this module's directory looking for the toolkit
83
105
  // root (i.e. a parent dir containing `skills/client-paths.json`).
@@ -86,14 +108,17 @@ function resolveManifest() {
86
108
  const candidate = join(dir, MANIFEST_REL);
87
109
  const m = tryReadManifest(candidate);
88
110
  if (m)
89
- return m;
111
+ return { manifest: m, toolkitRoot: dir };
90
112
  const parent = dirname(dir);
91
113
  if (parent === dir)
92
114
  break;
93
115
  dir = parent;
94
116
  }
95
117
  // 3. Bundled fallback (validated against the manifest by tests).
96
- return BUNDLED_MANIFEST;
118
+ return { manifest: BUNDLED_MANIFEST, toolkitRoot: null };
119
+ }
120
+ function resolveManifest() {
121
+ return resolveManifestWithRoot().manifest;
97
122
  }
98
123
  let cached = null;
99
124
  /**
@@ -102,11 +127,47 @@ let cached = null;
102
127
  * process).
103
128
  */
104
129
  export function loadClientPathsManifest() {
130
+ return getResolvedManifest().manifest;
131
+ }
132
+ /**
133
+ * Internal: the resolved manifest + the toolkit root it was loaded
134
+ * from. Cached after the first call.
135
+ */
136
+ function getResolvedManifest() {
105
137
  if (cached)
106
138
  return cached;
107
- cached = resolveManifest();
139
+ cached = resolveManifestWithRoot();
108
140
  return cached;
109
141
  }
142
+ /**
143
+ * Absolute path to the template skill file
144
+ * (`<toolkitRoot>/<manifest.templateRelativePath>`), resolved from the
145
+ * same root discovery that loads `client-paths.json`. Returns `null`
146
+ * when the toolkit root cannot be found (bundled-fallback / standalone
147
+ * `mcp-server/` install) so callers can degrade gracefully instead of
148
+ * guessing a path. Never throws.
149
+ *
150
+ * Used by the skill generator to merge the template workflow prose
151
+ * with the project-specific inventory (the template is the source of
152
+ * truth for the workflow playbook).
153
+ */
154
+ export function resolveTemplateSkillPath() {
155
+ const { manifest, toolkitRoot } = getResolvedManifest();
156
+ if (!toolkitRoot)
157
+ return null;
158
+ return join(toolkitRoot, manifest.templateRelativePath);
159
+ }
160
+ /**
161
+ * @internal Test-only cache reset. The manifest resolution is cached
162
+ * for process lifetime (it is immutable in production, where the env
163
+ * override is set before the process starts). Tests that mutate
164
+ * `UNITY_OPEN_MCP_TOOLKIT_ROOT` after a prior test already warmed the
165
+ * cache need this to observe the override. Do not call from runtime
166
+ * code.
167
+ */
168
+ export function _clearClientPathsCacheForTests() {
169
+ cached = null;
170
+ }
110
171
  /**
111
172
  * Project-relative skill path for a client key
112
173
  * (`cursor` / `claude` / `opencode` / `agents`). Throws for unknown
@@ -1 +1 @@
1
- {"version":3,"file":"client-paths.js","sourceRoot":"","sources":["../../src/skill/client-paths.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"client-paths.js","sourceRoot":"","sources":["../../src/skill/client-paths.ts"],"names":[],"mappings":"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"}
@@ -29,10 +29,49 @@ export interface GenerateSkillResult {
29
29
  project: ProjectState;
30
30
  written: SkillWriteTarget[];
31
31
  }
32
+ export interface GenerateSkillOptions {
33
+ write?: boolean;
34
+ clients?: string[];
35
+ /**
36
+ * When `true` (default), the generated skill composes the template
37
+ * workflow playbook (verbatim, the single source of truth for agent
38
+ * guidance) with the project-specific inventory section. When
39
+ * `false`, or when the template cannot be located, the generator
40
+ * falls back to its standalone full-inventory output.
41
+ */
42
+ includeWorkflow?: boolean;
43
+ }
32
44
  export declare function readProjectState(projectRoot: string): Promise<ProjectState>;
33
45
  export declare function generateSkillMarkdown(state: ProjectState, caps: CapabilitiesResult): string;
34
46
  export declare function writeSkillToClients(projectRoot: string, content: string, clients: string[]): Promise<SkillWriteTarget[]>;
35
- export declare function generateSkill(projectRoot: string, caps: CapabilitiesResult, options?: {
36
- write?: boolean;
37
- clients?: string[];
38
- }): Promise<GenerateSkillResult>;
47
+ /**
48
+ * Read the template workflow playbook from disk. Returns the template
49
+ * text (normalized to end with a single trailing newline), or `null`
50
+ * when the template cannot be located or read — the composer then
51
+ * degrades to the standalone full-inventory output. Never throws.
52
+ */
53
+ export declare function readTemplateWorkflow(): Promise<string | null>;
54
+ /**
55
+ * Compose the final skill markdown from the template playbook + the
56
+ * project inventory.
57
+ *
58
+ * - When `template` is non-null and `includeWorkflow !== false`: the
59
+ * template is emitted verbatim (the authoritative workflow prose),
60
+ * followed by a `---` separator and a `# Project inventory —
61
+ * <projectName>` section carrying the project-specific blocks. Both
62
+ * the template's heading and the project-name heading appear in the
63
+ * output.
64
+ * - When `template` is null (standalone install, template missing) or
65
+ * `includeWorkflow === false`: falls back to `generateSkillMarkdown`
66
+ * (the full standalone inventory, including its own workflow summary).
67
+ */
68
+ export declare function composeSkillMarkdown(state: ProjectState, caps: CapabilitiesResult, template: string | null, options?: {
69
+ includeWorkflow?: boolean;
70
+ }): string;
71
+ export declare function generateSkill(projectRoot: string, caps: CapabilitiesResult, options?: GenerateSkillOptions): Promise<GenerateSkillResult>;
72
+ /**
73
+ * Truncate a skill preview for embedding in a JSON envelope (Hub /
74
+ * CLI echo). The full skill is always written to disk when write=true;
75
+ * this only bounds the in-response copy.
76
+ */
77
+ export declare function truncateForPreview(skill: string): string;