the task takes a destination

output_dir, optional. absent, the text lands beside the recording as it
always has — that is what a person right-clicking a memo wants and it is
not changing. given, the transcript goes there instead, and the directory
is created if it does not exist.

for callers that are not a person clicking a file. a commander keeps its
results in its own directory, and the alternative was making every
commander move the file afterwards: a step in the loop forever, plus a
window where the file sits in the folder being watched.

marked `hidden` so the file browser neither shows it nor counts it as
something to ask about — without that, declaring it turned a direct
right-click run back into a modal with a field nobody clicking a file has
an answer for.
This commit is contained in:
2026-08-25 04:56:43 +00:00
parent dd3dbb611b
commit 8c0366fdbc
2 changed files with 36 additions and 11 deletions
+9 -2
View File
@@ -15,6 +15,13 @@ inputs:
- name: file_path - name: file_path
description: Path to the audio file to transcribe. Auto-filled from the file browser. description: Path to the audio file to transcribe. Auto-filled from the file browser.
required: true required: true
- name: output_dir
description: >-
Where to write the transcript. Absolute, or relative to the recording. Leave it out and the text
lands beside the recording, which is what a person clicking a file wants. A commander passes its own
directory so its results never land in the folder it watches.
required: false
hidden: true
trigger: trigger:
- type: file - type: file
extensions: extensions:
@@ -38,8 +45,8 @@ model call spent re-deriving what the plugin already returns.
(`GET /api/user/settings`). (`GET /api/user/settings`).
2. `POST` the file to `/api/transcribe/transcribe`. The plugin detects the language and transcribes 2. `POST` the file to `/api/transcribe/transcribe`. The plugin detects the language and transcribes
faithfully in it — see `plugins/transcribe/skills/transcribe/SKILL.md` for the contract. faithfully in it — see `plugins/transcribe/skills/transcribe/SKILL.md` for the contract.
3. Write the transcription beside the audio file, same name, `.md`. Nothing is moved and nothing is 3. Write the transcription as `.md` with the same base name — beside the recording by default, or into
created around it. `output_dir` when one is given. The directory is created if it does not exist.
It overwrites a previous transcription of the same file, deliberately: a transcription is derived, and It overwrites a previous transcription of the same file, deliberately: a transcription is derived, and
running it again means you wanted it again. running it again means you wanted it again.
+27 -9
View File
@@ -8,7 +8,8 @@
// only owns filing the result. // only owns filing the result.
import { existsSync } from 'node:fs'; import { existsSync } from 'node:fs';
import { basename, dirname, join, extname } from 'node:path'; import { mkdir } from 'node:fs/promises';
import { basename, dirname, isAbsolute, join, extname } from 'node:path';
const filePath = process.env.INPUT_FILE_PATH; const filePath = process.env.INPUT_FILE_PATH;
if (!filePath) { if (!filePath) {
@@ -69,14 +70,31 @@ async function main() {
const { text, detectedLanguage } = await transcribe(path, spokenLanguages); const { text, detectedLanguage } = await transcribe(path, spokenLanguages);
console.log(`Detected language: ${detectedLanguage}`); console.log(`Detected language: ${detectedLanguage}`);
// Beside the audio, same name, `.md`. Nothing is moved, nothing is created around it — this is the /*
// behaviour the file viewer's transcribe button had, and the one thing anybody wants from a Where the text goes.
// transcription is the text next to the recording it came from.
// By default, beside the audio with the same name — the behaviour the file viewer's transcribe button
// It overwrites a previous transcription of the same file deliberately: a transcription is derived, had, and what a person right-clicking a recording wants: the text turns up next to the thing it came
// running it again means you wanted it again, and a `-2` beside it would only be a second file to from.
// read and choose between.
const transcriptPath = join(dirname(path), `${basename(path, extname(path))}.md`); `output_dir` overrides it, and exists for callers that are not a person clicking a file. A commander
keeps its results in its OWN directory: writing them into the folder it watches would put its work in
the middle of its subject, where nobody asked for it and where its next pass has to tell the two
apart. Passing a destination is one input; making every such caller move the file afterwards is a
step in every loop, forever, and a window where the file is in the wrong place.
Created if missing, so a caller does not have to make the directory first — the first run of a new
commander otherwise fails on a directory only this script knows the name of.
Either way it overwrites a previous transcription of the same recording, deliberately: a
transcription is derived, running it again means you wanted it again, and a `-2` beside it would only
be a second file to read and choose between.
*/
const outputDir = process.env.INPUT_OUTPUT_DIR?.trim();
const destDir = outputDir ? (isAbsolute(outputDir) ? outputDir : join(dirname(path), outputDir)) : dirname(path);
if (outputDir) await mkdir(destDir, { recursive: true });
const transcriptPath = join(destDir, `${basename(path, extname(path))}.md`);
await Bun.write(transcriptPath, text); await Bun.write(transcriptPath, text);
console.log(transcriptPath); console.log(transcriptPath);