Skip to content

Commit 746e09a

Browse files
committed
fix(cli): skills bundler resolves caller-relative paths + correct dev layout
Two correctness fixes caught during end-to-end validation: 1. Resolve skill.path relative to the file that called skills.define(), not the project root. The resource catalog already captures filePath on each SkillManifest — use it to compute the source folder. 2. In dev, copy skill bundles to {workingDir}/.trigger/skills/ (where the worker's cwd resolves). In deploy, keep copying to {outputPath}/.trigger/skills/ so the Dockerfile COPY . /app lands them at /app/.trigger/skills/. Also upgrade the skill-discovery failure log from debug to warn so config mistakes surface in the dev console instead of disappearing silently. Finally, update the ai-chat reference's aiChat.run() to pass chatTools through chat.toStreamTextOptions({ tools: chatTools }) instead of spreading them after — the auto-injected loadSkill/readFile/bash tools would otherwise get overwritten by the explicit tools: chatTools key.
1 parent dcb86ba commit 746e09a

4 files changed

Lines changed: 26 additions & 8 deletions

File tree

packages/cli-v3/src/build/buildWorker.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ export async function buildWorker(options: BuildWorkerOptions) {
120120
});
121121
buildManifest = skillsResult.buildManifest;
122122
} catch (err) {
123-
logger.debug("Skill bundling failed; continuing without skills", err);
123+
logger.warn("Skill bundling failed; continuing without skills", err);
124124
}
125125

126126
buildManifest = await notifyExtensionOnBuildComplete(buildContext, buildManifest);

packages/cli-v3/src/build/bundleSkills.ts

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { createHash } from "node:crypto";
22
import { readFile } from "node:fs/promises";
3-
import { dirname, join, resolve as resolvePath } from "node:path";
3+
import { dirname, isAbsolute, join, resolve as resolvePath } from "node:path";
44
import type { BuildManifest, SkillManifest } from "@trigger.dev/core/v3/schemas";
55
import { copyDirectoryRecursive } from "@trigger.dev/build/internal";
66
import { indexWorkerManifest } from "../indexing/indexWorkerManifest.js";
@@ -60,19 +60,37 @@ export async function bundleSkills(
6060
} catch (err) {
6161
// Skill discovery via the indexer is best-effort — if the user's
6262
// bundle doesn't load cleanly here the downstream full indexer will
63-
// surface the real error. Warn and continue with no skills.
64-
logger.debug(`[bundleSkills] skill discovery failed: ${(err as Error).message}`);
63+
// surface the real error. Warn so the user sees what went wrong.
64+
logger.warn(
65+
`[bundleSkills] skill discovery failed, skipping skill bundling: ${(err as Error).message}`
66+
);
6567
return { buildManifest, skills: [] };
6668
}
6769

6870
if (skills.length === 0) {
6971
return { buildManifest, skills: [] };
7072
}
7173

72-
const destinationRoot = join(buildManifest.outputPath, ".trigger", "skills");
74+
// Destination layout differs between dev and deploy:
75+
// - Dev: the worker runs with cwd = workingDir, so skills must live at
76+
// {workingDir}/.trigger/skills/{id}/ for skill.local() to find them.
77+
// - Deploy: the Dockerfile COPY picks up everything under outputPath into
78+
// /app, so we target {outputPath}/.trigger/skills/{id}/ and the
79+
// container's cwd (/app) resolves correctly.
80+
const destinationRoot =
81+
buildManifest.target === "dev"
82+
? join(workingDir, ".trigger", "skills")
83+
: join(buildManifest.outputPath, ".trigger", "skills");
7384

7485
for (const skill of skills) {
75-
const sourcePath = resolvePath(workingDir, skill.sourcePath);
86+
// Resolve the skill's source folder relative to the file that called
87+
// `skills.define(...)`. Absolute paths are honored as-is.
88+
const callerDir = skill.filePath
89+
? dirname(resolvePath(workingDir, skill.filePath))
90+
: workingDir;
91+
const sourcePath = isAbsolute(skill.sourcePath)
92+
? skill.sourcePath
93+
: resolvePath(callerDir, skill.sourcePath);
7694
const skillMdPath = join(sourcePath, "SKILL.md");
7795

7896
let skillMd: string;

packages/cli-v3/src/dev/devSession.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ export async function startDevSession({
136136
});
137137
buildManifest = skillsResult.buildManifest;
138138
} catch (err) {
139-
logger.debug("Skill bundling failed during dev rebuild", err);
139+
logger.warn("Skill bundling failed during dev rebuild", err);
140140
}
141141

142142
buildManifest = await notifyExtensionOnBuildComplete(buildContext, buildManifest);

references/ai-chat/src/trigger/chat.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -495,10 +495,10 @@ export const aiChat = chat
495495
...chat.toStreamTextOptions({
496496
registry,
497497
telemetry: clientData?.userId ? { userId: clientData.userId } : undefined,
498+
tools: chatTools,
498499
}),
499500
model: languageModelForChatTurn(modelOverride),
500501
messages: messages,
501-
tools: chatTools,
502502
stopWhen: stepCountIs(10),
503503
abortSignal: stopSignal,
504504
providerOptions: {

0 commit comments

Comments
 (0)