refactor(cli): tell a compiled binary by a build define and give a missing skill its own error code

This commit is contained in:
GareArc
2026-10-16 00:51:38 +00:00
committed by GitHub
parent da918ced8e
commit d6722d850e
9 changed files with 28 additions and 23 deletions
+1
View File
@@ -9,6 +9,7 @@ globalThis.__DIFYCTL_VERSION__ = info.version
globalThis.__DIFYCTL_COMMIT__ = info.commit
globalThis.__DIFYCTL_BUILD_DATE__ = info.buildDate
globalThis.__DIFYCTL_CHANNEL__ = info.channel
globalThis.__DIFYCTL_COMPILED__ = false
const { main } = await import('../src/main.ts')
process.exitCode = await main(process.argv.slice(2))
+3
View File
@@ -57,6 +57,7 @@ defines=(
"--define" "__DIFYCTL_CHANNEL__=\"${DIFYCTL_CHANNEL}\""
"--define" "__DIFYCTL_COMMIT__=\"${DIFYCTL_COMMIT}\""
"--define" "__DIFYCTL_BUILD_DATE__=\"${DIFYCTL_BUILD_DATE}\""
"--define" "__DIFYCTL_COMPILED__=true"
)
# Targets and asset names come from cli/package.json `difyctl.release` via
@@ -64,6 +65,8 @@ defines=(
while IFS=$'\t' read -r bun_target asset_target _exe; do
out="${out_dir}/$(naming asset "$CLI_VERSION" "$asset_target")"
log::info "compiling ${asset_target} -> $(basename "$out")..."
# Run from the repo root: --asset paths are embedded relative to the cwd, which gives
# the skill its difyctl/ prefix.
(cd "$repo_root" && bun build "$entry" \
--asset "$skill_dir" \
--target="$bun_target" \
+2
View File
@@ -14,6 +14,7 @@ export const ErrorCode = {
RateLimited: 'rate_limited',
ServerError: 'server_error',
KeyringUnavailable: 'keyring_unavailable',
SkillMissing: 'skill_missing',
Unknown: 'unknown',
} as const
@@ -47,6 +48,7 @@ const CODE_TO_EXIT: Readonly<Record<ErrorCodeValue, ExitCodeValue>> = {
rate_limited: ExitCode.RateLimited,
server_error: ExitCode.Generic,
keyring_unavailable: ExitCode.Generic,
skill_missing: ExitCode.Generic,
unknown: ExitCode.Generic,
}
+15 -14
View File
@@ -11,7 +11,7 @@ export const SKILL_NAME = 'difyctl'
export const SKILL_FILE = 'SKILL.md'
const EMBED_PREFIX = `${SKILL_NAME}/`
const REPO_SKILL_DIR = fileURLToPath(new URL(`../../../skills/${EMBED_PREFIX}`, import.meta.url))
export const NO_EMBEDDED_SKILL =
const NO_EMBEDDED_SKILL =
'this difyctl build has no embedded skill; reinstall difyctl or pass --from <folder>'
export type SkillSource = {
@@ -44,29 +44,30 @@ export async function openDir(root: string): Promise<SkillSource> {
return { paths, read: (path) => readFile(join(root, path)) }
}
export function embeddedSource(files: readonly EmbeddedFile[]): SkillSource {
function embeddedSource(files: readonly EmbeddedFile[]): SkillSource {
const byPath = new Map(files.map((file) => [file.name.slice(EMBED_PREFIX.length), file]))
return {
paths: [...byPath.keys()],
read: async (path) => new Uint8Array(await (byPath.get(path) as EmbeddedFile).arrayBuffer()),
read: async (path) => {
const file = byPath.get(path)
if (file === undefined)
throw new BaseError({
code: ErrorCode.SkillMissing,
message: `the embedded skill has no ${path}`,
})
return new Uint8Array(await file.arrayBuffer())
},
}
}
export type SourceInputs = Readonly<{ files: readonly EmbeddedFile[]; compiled: boolean }>
export async function pickSource({ files, compiled }: SourceInputs): Promise<SkillSource> {
async function defaultSource(): Promise<SkillSource> {
const files = embeddedFiles().filter((file) => file.name.startsWith(EMBED_PREFIX))
if (files.length > 0) return embeddedSource(files)
if (compiled) throw new BaseError({ code: ErrorCode.Unknown, message: NO_EMBEDDED_SKILL })
if (isCompiledBinary())
throw new BaseError({ code: ErrorCode.SkillMissing, message: NO_EMBEDDED_SKILL })
return openDir(REPO_SKILL_DIR)
}
export function defaultSource(): Promise<SkillSource> {
return pickSource({
files: embeddedFiles().filter((file) => file.name.startsWith(EMBED_PREFIX)),
compiled: isCompiledBinary(),
})
}
export function openSource(from: string | undefined): Promise<SkillSource> {
return from === undefined ? defaultSource() : openDir(from)
}
+3 -9
View File
@@ -8,20 +8,14 @@ export function getEnv(name: string): string | undefined {
export type EmbeddedFile = Blob & { readonly name: string }
type BunGlobal = { embeddedFiles?: readonly EmbeddedFile[]; main?: string }
const COMPILED_ENTRY = /^(?:\/\$bunfs\/|[A-Z]:[\\/]~BUN[\\/])/i
function bun(): BunGlobal | undefined {
return (globalThis as { Bun?: BunGlobal }).Bun
}
type BunGlobal = { embeddedFiles?: readonly EmbeddedFile[] }
export function embeddedFiles(): readonly EmbeddedFile[] {
return bun()?.embeddedFiles ?? []
return (globalThis as { Bun?: BunGlobal }).Bun?.embeddedFiles ?? []
}
export function isCompiledBinary(): boolean {
return COMPILED_ENTRY.test(bun()?.main ?? '')
return __DIFYCTL_COMPILED__
}
export function env(): NodeJS.ProcessEnv {
+1
View File
@@ -4,3 +4,4 @@ declare const __DIFYCTL_VERSION__: string
declare const __DIFYCTL_COMMIT__: string
declare const __DIFYCTL_BUILD_DATE__: string
declare const __DIFYCTL_CHANNEL__: string
declare const __DIFYCTL_COMPILED__: boolean
+1
View File
@@ -3,3 +3,4 @@
;(globalThis as unknown as Record<string, string>).__DIFYCTL_BUILD_DATE__ =
'1970-01-01T00:00:00.000Z'
;(globalThis as unknown as Record<string, string>).__DIFYCTL_CHANNEL__ = 'dev'
;(globalThis as unknown as Record<string, boolean>).__DIFYCTL_COMPILED__ = false
+1
View File
@@ -29,6 +29,7 @@ export default defineConfig({
__DIFYCTL_COMMIT__: JSON.stringify(buildInfo.commit),
__DIFYCTL_BUILD_DATE__: JSON.stringify(buildInfo.buildDate),
__DIFYCTL_CHANNEL__: JSON.stringify(buildInfo.channel),
__DIFYCTL_COMPILED__: 'false',
},
},
test: {
+1
View File
@@ -49,6 +49,7 @@ export default defineConfig({
__DIFYCTL_COMMIT__: JSON.stringify(buildInfo.commit),
__DIFYCTL_BUILD_DATE__: JSON.stringify(buildInfo.buildDate),
__DIFYCTL_CHANNEL__: JSON.stringify(buildInfo.channel),
__DIFYCTL_COMPILED__: 'false',
},
},
test: {