@lingochunk/mcp 0.3.1 → 0.9.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.
- package/README.md +114 -11
- package/dist/client.d.ts +207 -0
- package/dist/client.js +164 -0
- package/dist/client.js.map +1 -1
- package/dist/config.d.ts +23 -0
- package/dist/config.js +41 -14
- package/dist/config.js.map +1 -1
- package/dist/generated/guides.d.ts +13 -0
- package/dist/generated/guides.js +50 -0
- package/dist/generated/guides.js.map +1 -0
- package/dist/http.d.ts +22 -0
- package/dist/http.js +174 -0
- package/dist/http.js.map +1 -0
- package/dist/index.js +13 -1
- package/dist/index.js.map +1 -1
- package/dist/prompts.d.ts +13 -0
- package/dist/prompts.js +26 -0
- package/dist/prompts.js.map +1 -0
- package/dist/tools.d.ts +7 -1
- package/dist/tools.js +807 -56
- package/dist/tools.js.map +1 -1
- package/package.json +4 -2
package/dist/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|
package/dist/config.d.ts
CHANGED
|
@@ -7,6 +7,29 @@ export interface Config {
|
|
|
7
7
|
/** Directory audio clips are written to (get_audio_clip returns the file path). */
|
|
8
8
|
clipDir: string;
|
|
9
9
|
}
|
|
10
|
+
/** Configuration for the hosted (Streamable HTTP) mode: no token here - each
|
|
11
|
+
* request carries its own caller's Bearer credential. */
|
|
12
|
+
export interface HttpConfig {
|
|
13
|
+
/** Base origin of the LingoChunk API the server proxies to. */
|
|
14
|
+
baseUrl: string;
|
|
15
|
+
/** TCP port to listen on. */
|
|
16
|
+
port: number;
|
|
17
|
+
/** PUBLIC origin of the deployment, for URLs handed to clients (OAuth
|
|
18
|
+
* discovery). Distinct from baseUrl, which is the in-network upstream. */
|
|
19
|
+
publicOrigin: string;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Build the hosted-mode config from environment variables.
|
|
23
|
+
*
|
|
24
|
+
* - LINGOCHUNK_BASE_URL (optional) API origin; when co-located with the
|
|
25
|
+
* API prefer the loopback origin (e.g. http://127.0.0.1:8000) to skip the
|
|
26
|
+
* reverse proxy.
|
|
27
|
+
* - LINGOCHUNK_MCP_PORT (optional) listen port, default 8100. PORT is
|
|
28
|
+
* honoured as a fallback for PaaS conventions.
|
|
29
|
+
* - LINGOCHUNK_PUBLIC_ORIGIN (optional) the origin clients see (default the
|
|
30
|
+
* production site); used to build OAuth discovery URLs in 401 responses.
|
|
31
|
+
*/
|
|
32
|
+
export declare function loadHttpConfig(env?: NodeJS.ProcessEnv): HttpConfig;
|
|
10
33
|
/**
|
|
11
34
|
* Build the config from environment variables.
|
|
12
35
|
*
|
package/dist/config.js
CHANGED
|
@@ -1,6 +1,46 @@
|
|
|
1
1
|
import os from "node:os";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
const DEFAULT_BASE_URL = "https://lingochunk.com";
|
|
4
|
+
const DEFAULT_HTTP_PORT = 8100;
|
|
5
|
+
/**
|
|
6
|
+
* Build the hosted-mode config from environment variables.
|
|
7
|
+
*
|
|
8
|
+
* - LINGOCHUNK_BASE_URL (optional) API origin; when co-located with the
|
|
9
|
+
* API prefer the loopback origin (e.g. http://127.0.0.1:8000) to skip the
|
|
10
|
+
* reverse proxy.
|
|
11
|
+
* - LINGOCHUNK_MCP_PORT (optional) listen port, default 8100. PORT is
|
|
12
|
+
* honoured as a fallback for PaaS conventions.
|
|
13
|
+
* - LINGOCHUNK_PUBLIC_ORIGIN (optional) the origin clients see (default the
|
|
14
|
+
* production site); used to build OAuth discovery URLs in 401 responses.
|
|
15
|
+
*/
|
|
16
|
+
export function loadHttpConfig(env = process.env) {
|
|
17
|
+
const baseUrl = validateBaseUrl(env.LINGOCHUNK_BASE_URL ?? DEFAULT_BASE_URL);
|
|
18
|
+
const publicOrigin = validateBaseUrl(env.LINGOCHUNK_PUBLIC_ORIGIN ?? DEFAULT_BASE_URL);
|
|
19
|
+
const rawPort = (env.LINGOCHUNK_MCP_PORT ?? env.PORT ?? "").trim();
|
|
20
|
+
const port = rawPort ? Number(rawPort) : DEFAULT_HTTP_PORT;
|
|
21
|
+
if (!Number.isInteger(port) || port < 1 || port > 65535) {
|
|
22
|
+
throw new Error(`LINGOCHUNK_MCP_PORT must be an integer in 1-65535, got: ${rawPort}`);
|
|
23
|
+
}
|
|
24
|
+
return { baseUrl, port, publicOrigin };
|
|
25
|
+
}
|
|
26
|
+
/** Normalise and validate an API origin, throwing a clear onboarding error. */
|
|
27
|
+
function validateBaseUrl(raw) {
|
|
28
|
+
const baseUrl = raw.replace(/\/+$/, "");
|
|
29
|
+
// Fail fast on a malformed origin rather than throwing an opaque error on the
|
|
30
|
+
// first request. A bare host like "localhost:8000" parses with a bogus scheme,
|
|
31
|
+
// so also require http(s).
|
|
32
|
+
let parsed;
|
|
33
|
+
try {
|
|
34
|
+
parsed = new URL(baseUrl);
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
throw new Error(`LINGOCHUNK_BASE_URL is not a valid URL: ${baseUrl}`);
|
|
38
|
+
}
|
|
39
|
+
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
|
|
40
|
+
throw new Error(`LINGOCHUNK_BASE_URL must be an http(s) URL (e.g. https://lingochunk.com), got: ${baseUrl}`);
|
|
41
|
+
}
|
|
42
|
+
return baseUrl;
|
|
43
|
+
}
|
|
4
44
|
/**
|
|
5
45
|
* Build the config from environment variables.
|
|
6
46
|
*
|
|
@@ -20,20 +60,7 @@ export function loadConfig(env = process.env) {
|
|
|
20
60
|
"LingoChunk account settings and pass it as LINGOCHUNK_TOKEN (it starts " +
|
|
21
61
|
"with 'lcp_').");
|
|
22
62
|
}
|
|
23
|
-
const baseUrl = (env.LINGOCHUNK_BASE_URL ?? DEFAULT_BASE_URL)
|
|
24
|
-
// Fail fast on a malformed origin rather than throwing an opaque error on the
|
|
25
|
-
// first request. A bare host like "localhost:8000" parses with a bogus scheme,
|
|
26
|
-
// so also require http(s).
|
|
27
|
-
let parsed;
|
|
28
|
-
try {
|
|
29
|
-
parsed = new URL(baseUrl);
|
|
30
|
-
}
|
|
31
|
-
catch {
|
|
32
|
-
throw new Error(`LINGOCHUNK_BASE_URL is not a valid URL: ${baseUrl}`);
|
|
33
|
-
}
|
|
34
|
-
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
|
|
35
|
-
throw new Error(`LINGOCHUNK_BASE_URL must be an http(s) URL (e.g. https://lingochunk.com), got: ${baseUrl}`);
|
|
36
|
-
}
|
|
63
|
+
const baseUrl = validateBaseUrl(env.LINGOCHUNK_BASE_URL ?? DEFAULT_BASE_URL);
|
|
37
64
|
// Default to a private per-user cache dir rather than the world-readable
|
|
38
65
|
// shared temp dir: clips are the user's own study audio, so they should not
|
|
39
66
|
// land somewhere every account on the machine can read.
|
package/dist/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAY7B,MAAM,gBAAgB,GAAG,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAY7B,MAAM,gBAAgB,GAAG,wBAAwB,CAAC;AAclD,MAAM,iBAAiB,GAAG,IAAI,CAAC;AAE/B;;;;;;;;;;GAUG;AACH,MAAM,UAAU,cAAc,CAAC,MAAyB,OAAO,CAAC,GAAG;IACjE,MAAM,OAAO,GAAG,eAAe,CAAC,GAAG,CAAC,mBAAmB,IAAI,gBAAgB,CAAC,CAAC;IAC7E,MAAM,YAAY,GAAG,eAAe,CAClC,GAAG,CAAC,wBAAwB,IAAI,gBAAgB,CACjD,CAAC;IACF,MAAM,OAAO,GAAG,CAAC,GAAG,CAAC,mBAAmB,IAAI,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IACnE,MAAM,IAAI,GAAG,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,iBAAiB,CAAC;IAC3D,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,IAAI,GAAG,CAAC,IAAI,IAAI,GAAG,KAAK,EAAE,CAAC;QACxD,MAAM,IAAI,KAAK,CACb,2DAA2D,OAAO,EAAE,CACrE,CAAC;IACJ,CAAC;IACD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,CAAC;AACzC,CAAC;AAED,+EAA+E;AAC/E,SAAS,eAAe,CAAC,GAAW;IAClC,MAAM,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IACxC,8EAA8E;IAC9E,+EAA+E;IAC/E,2BAA2B;IAC3B,IAAI,MAAW,CAAC;IAChB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC;IAC5B,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,KAAK,CAAC,2CAA2C,OAAO,EAAE,CAAC,CAAC;IACxE,CAAC;IACD,IAAI,MAAM,CAAC,QAAQ,KAAK,OAAO,IAAI,MAAM,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAChE,MAAM,IAAI,KAAK,CACb,kFAAkF,OAAO,EAAE,CAC5F,CAAC;IACJ,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,UAAU,CAAC,MAAyB,OAAO,CAAC,GAAG;IAC7D,MAAM,KAAK,GAAG,CAAC,GAAG,CAAC,gBAAgB,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IAClD,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,IAAI,KAAK,CACb,uEAAuE;YACrE,yEAAyE;YACzE,eAAe,CAClB,CAAC;IACJ,CAAC;IAED,MAAM,OAAO,GAAG,eAAe,CAAC,GAAG,CAAC,mBAAmB,IAAI,gBAAgB,CAAC,CAAC;IAE7E,yEAAyE;IACzE,4EAA4E;IAC5E,wDAAwD;IACxD,MAAM,OAAO,GACX,GAAG,CAAC,mBAAmB,EAAE,IAAI,EAAE;QAC/B,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,QAAQ,EAAE,gBAAgB,CAAC,CAAC;IAEtD,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;AACrC,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export type GuideTopic = "overview" | "lesson" | "course" | "cards" | "annotations" | "add-language" | "discuss";
|
|
2
|
+
export interface Guide {
|
|
3
|
+
/** The public topic value (get_authoring_guide's `topic` argument). */
|
|
4
|
+
topic: GuideTopic;
|
|
5
|
+
/** The MCP prompt name (`lingochunk-<skill>`). */
|
|
6
|
+
promptName: string;
|
|
7
|
+
/** One-line description / trigger text, from the skill frontmatter. */
|
|
8
|
+
description: string;
|
|
9
|
+
/** The full skill markdown, frontmatter stripped. */
|
|
10
|
+
body: string;
|
|
11
|
+
}
|
|
12
|
+
export declare const GUIDE_TOPICS: readonly GuideTopic[];
|
|
13
|
+
export declare const GUIDES: Record<GuideTopic, Guide>;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
// AUTO-GENERATED by scripts/generate-guides.ts from skills/*/SKILL.md.
|
|
2
|
+
// Do not edit by hand: `npm run build` regenerates it. The authoring
|
|
3
|
+
// skills are embedded here because the npm package ships only dist/, so
|
|
4
|
+
// remote MCP clients cannot read skills/ off disk.
|
|
5
|
+
export const GUIDE_TOPICS = ["overview", "lesson", "course", "cards", "annotations", "add-language", "discuss"];
|
|
6
|
+
export const GUIDES = {
|
|
7
|
+
"overview": {
|
|
8
|
+
topic: "overview",
|
|
9
|
+
promptName: "lingochunk-overview",
|
|
10
|
+
description: "Give a short guided tour of what the user can do with their LingoChunk connection, then go deeper on the area they pick. Use when the user asks what they can do with LingoChunk, what is possible, how to get started, says \"help\" about the connection, or is exploring it for the first time.",
|
|
11
|
+
body: "# What you can do with LingoChunk\n\nYou are connected to the user's LingoChunk account: their episodes with\ntimestamped transcripts and native audio, their FSRS-graded vocabulary, their\ndecks and lessons, and (for creators) the collections they publish. This\nguide is the menu of what to offer.\n\n## How to answer \"what can I do?\"\n\n- **Answer short first**: one line per area below, each with its example\n prompt. Do NOT dump this whole guide on the user.\n- **Then ask which area to go deeper on** - or just do the thing they pick.\n- Before actually composing anything, call `get_authoring_guide` with the\n area's topic (in parentheses below) and follow it; that is where the craft\n rules live. Areas marked \"no guide\" need no preparation.\n- If a tool answers 403 naming a scope, the connection was granted narrow\n permissions: tell the user to reconnect (or mint a token with that scope)\n via LingoChunk -> Settings -> API tokens.\n\n## The menu\n\nFor every learner:\n\n1. **Talk through an episode** (topic `discuss`) - work through a real\n episode conversationally, explaining grammar and vocabulary as they come\n up, grounded in the user's own data.\n Example: *\"Talk me through yesterday's episode and explain the tricky\n bits.\"*\n2. **Check words and quiz** (no guide) - the user's vocabulary with live\n maturity states: known, learning, new, due.\n Example: *\"Which of my German words are due today? Quiz me on them.\"*\n3. **Build a lesson** (topic `lesson`) - a coursebook-style lesson the app\n renders natively: real-audio exercises, gap-fills, dictation, shadowing,\n one grammar point, an AI tutor, an offline worksheet download.\n Example: *\"Build a B1 lesson from the first five minutes of episode 12.\"*\n4. **Revise a lesson** (topic `lesson`) - edit a saved lesson IN PLACE\n (same id and links): the app's Co-edit mode labels each block §1, §2, ...\n and refreshes live, so the user points at a block and watches your edit\n land within seconds.\n Example: *\"In my lesson, change §5 to a two-person dialogue.\"*\n5. **Build a course** (topic `course`) - a named, ordered series of lessons\n with a different grammar point per lesson and ramping difficulty.\n Example: *\"Turn this 20-minute episode into a four-lesson course, A2 to\n B1.\"*\n6. **Make flashcards and export to Anki** (topic `cards`) - native-grade\n cards anchored to verbatim sentences (highlight/blur painting, native\n audio clip), plus `.apkg` deck export.\n Example: *\"Make cards for the idioms in episode 12, then export the deck\n to Anki.\"*\n7. **Add languages** (topic `add-language`) - fan an episode out into up to\n ten more languages server-side, or hand-craft the translation sentence by\n sentence - including simplified same-language versions (e.g. German audio\n glossed in easier A2 German).\n Example: *\"Add Polish and Turkish to episode 12.\"* or *\"Make a simplified\n German (A2) version of it.\"*\n\nFor creators (per-account features):\n\n8. **Creator notes** (topic `annotations`) - short notes pinned to the exact\n idioms, fixed phrases and cultural references in the transcript; followers\n see them as highlights with a note sheet, and as note cards.\n Example: *\"Annotate the useful expressions in episode 12 for my\n students.\"*\n9. **Publish to an audience** (topic `lesson`) - lessons save private by\n default; saving with visibility `public` surfaces one to everyone who can\n view the episode, e.g. followers of the creator's channel.\n Example: *\"Build a lesson from episode 12 and publish it to my channel.\"*\n\n## Worth knowing (relay when relevant)\n\n- Everything is grounded in the user's own content: quotes, sentence\n positions and audio windows are validated server-side, so an invented or\n misquoted line is rejected rather than stored.\n- The app renders lessons natively with the real episode audio and live word\n knowledge; nothing here generates synthetic speech.\n- Composition runs on this agent; it never spends LingoChunk's AI budget.\n- The connection is revocable at any time in Settings -> API tokens.\n- Creators get the full picture (setup, workflows, best practices, example\n prompts) in the creator guide:\n https://github.com/lingochunk/mcp/blob/main/docs/creator-guide.md",
|
|
12
|
+
},
|
|
13
|
+
"lesson": {
|
|
14
|
+
topic: "lesson",
|
|
15
|
+
promptName: "lingochunk-lesson",
|
|
16
|
+
description: "Build a coursebook-style lesson from the user's own LingoChunk listening history and save it as a structured lesson.v1 document. Pick an episode (optionally a time range like \"the first 5 minutes\") and a CEFR level, pull the transcript slice plus vocabulary with FSRS maturity, then compose a lesson on a Listen -> Text -> Vocabulary -> Grammar -> Exercises -> Review scaffold, choosing 2-3 exercise archetypes suited to the grammar point and level so consecutive lessons don't feel identical. The app renders it natively with real audio, live word state, crosslinks and a built-in AI tutor. Use when the user asks to make or build a lesson, worksheet, study sheet, or exercises from their LingoChunk content, or to \"quiz me\" on an episode or a word.",
|
|
17
|
+
body: "# LingoChunk lesson builder\n\nBuild a `lesson.v1` document grounded in the learner's real LingoChunk\ncontent. The division of labour is the point: **LingoChunk supplies the\nmaterials (sentences with positions and translations, vocabulary with FSRS\nmaturity) and renders the lesson natively in the app; you do the pedagogy on\nthe user's own tokens.** No server-side LLM spend. The app plays the audio\nstraight from the original episode (never send or embed audio), resolves\nword knowledge live, links every word and sentence back to its Words/Listen\ntabs, and mounts an Ask AI tutor on the grammar box and glossary.\n\nThis skill uses the `lingochunk` MCP tools. If they are not available, tell\nthe user to add the LingoChunk MCP server (see the plugin README) and stop.\n\n## When to use\n\n- \"Make me a lesson / worksheet / quiz from yesterday's episode.\"\n- \"Build a lesson on the subjunctive using examples from my episodes.\"\n- \"Create a lesson from the first five minutes of episode X.\"\n- \"Quiz me on the words I'm learning in German.\"\n\n## Options to settle first (ask only what the user left open)\n\n1. **Source**: a named episode (`list_library`), or a topic/grammar point\n gathered across episodes (`search_examples`, `get_vocabulary`) - in v1 a\n lesson has ONE source episode, so for cross-episode topics pick the\n richest single episode.\n2. **Time range**: \"the first five minutes\" maps to `get_transcript`\n `from_time`/`to_time`; a chapter or scene works too. Default: a coherent\n 3 to 8 minute slice, not a whole 45-minute episode.\n3. **Level**: the CEFR level to pitch at. If the user does not say, infer it\n from the CEFR mix of their `get_vocabulary(status=known)` words and say\n which level you picked. Level drives:\n - instruction language: A1/A2 instructions in the learner's language;\n B1+ in the target language (keep them one short sentence);\n - exercise mix: more recognition (MCQ, matching) at low levels, more\n cued recall and production at high levels;\n - which grammar point qualifies (see below), glossary depth, and which\n archetypes you pick from the menu.\n\n## Workflow\n\n1. **Pull the slice.** `get_transcript` with the chosen range. Only\n `transcript_state: \"ready\"` is usable. Keep each sentence's `position`,\n `text`, `translation`, `speaker`, and its `start`/`end` seconds - the\n document references sentences BY POSITION and must quote `text` VERBATIM\n (the server rejects misquotes); the `start`/`end` times are what you build\n `audio_slice` windows from.\n\n2. **Gather and filter vocabulary.** Two sets: EXCLUDE and DRILL.\n - Exclusion set: `get_vocabulary(status=known)` (follow `next_cursor`\n with `limit=200` until null, or a known word slips into an exercise).\n - Due words: `get_vocabulary(status=due)` - do NOT exclude; they are\n exactly what is worth practising now (the app flags them live).\n - Drill words: `get_vocabulary(status=learning)` and `status=new`,\n prioritised.\n - Ground meanings/gender/CEFR with `lookup_word`; never invent them.\n\n3. **Pick ONE grammar point** evidenced in the slice, at the lesson's\n level. One per lesson, always. Prefer a pattern that occurs 2+ times in\n the slice so the evidence table has real rows.\n\n4. **Compose the document** (schema below) on the scaffold, choosing\n archetypes from the menu. The scaffold is the default skeleton; the\n archetype menu is what stops every lesson looking the same. See\n \"The scaffold and the archetype menu\" below.\n\n5. **Validate, then save.** Call `validate_lesson` with `{document}` FIRST:\n it returns EVERY problem at once (schema + reference), so you fix the whole\n document in one pass instead of burning save -> 400 -> fix cycles. Read the\n `errors` codes: `schema_invalid` carries a `loc` (dotted path to the bad\n field); `unknown_positions` / `position_outside_slice` mean a sentence\n reference is wrong; `dialogue_mismatch` means quote the transcript verbatim\n (including punctuation); `order_mismatch` means an `exercise_order` item's\n segments do not reassemble its anchored sentence. Only once it returns\n `valid: true` do you `save_lesson` with `{document}`. Set\n `generator: {skill: \"lingochunk-lesson\"}` so the app's lessons list shows\n which skill built it (episodes collect lessons from several skills). Both\n calls report `unknown_lemmas` (advisory only - glossary lemmas the episode\n does not know); prefer the lemma form the episode's vocabulary uses and fix\n any that look wrong before saving.\n\n6. **Deliver.** Give the user the `app_url` (the lesson opens in a Lessons\n tab on the episode). If the user asked for a course or a series of lessons,\n file this one under a course: `create_course` once, then pass its id as\n `save_lesson`'s `course_id` with a `sequence` (see the `lingochunk-course`\n guide). If the user is a CREATOR publishing to their audience, pass\n `visibility: \"public\"` too - the lesson then shows to everyone who can view\n the episode (e.g. followers of their collection). Publishing requires\n owning the episode; the default is private, so never publish unasked. Offer `add_card` for drill words the lesson introduced (a 409 means\n it is already there - skip and carry on; never add `status=known` words).\n Mention the in-app Download button if they want the offline HTML worksheet\n (it has no audio by design). Summarise what the lesson covers and which\n words it drills.\n\n## Revising a saved lesson\n\nLessons are editable IN PLACE: `get_lesson` -> compose the change ->\n`update_lesson`. The lesson keeps its id, app_url, visibility and course, so\nnever revise by save-new + delete-old.\n\n**The co-edit loop.** The app has a Co-edit mode for lesson owners: it labels\nevery block with a § handle (§1, §2, ... - the 1-based block position) and\nlive-refreshes while an agent edits. When the user pastes a lesson outline or\nsays \"change §5\", they are in that loop: the § numbers are `update_lesson`'s\n`ops` block numbers, and the user SEES your edit land within seconds - so\nact, then confirm briefly; no need to re-describe the lesson.\n\nWorkflow:\n\n1. `get_lesson` returns `{version, document}`. Treat `version` as OPAQUE -\n echo it verbatim as `update_lesson`'s `base_version`, never parse or\n reformat it (a Date round-trip truncates it and it will never match).\n2. Compose the revision against THAT read. Every rule in this guide applies\n to edited blocks - verbatim transcript quotes, anchoring, one grammar\n point. For a broad rewrite, `validate_lesson` the whole revised document\n first; for surgical `ops`, the update re-validates server-side anyway.\n3. Prefer `ops` (replace/insert/delete by block number, plus `meta` for\n title/subtitle/level/objectives) over a full `document` resend. Batch ALL\n changes from one read into ONE call, ordered by DESCENDING block number -\n ops apply sequentially, so editing top-down shifts the numbers under you.\n4. § numbers are only valid against the read they came from. After your own\n successful update everything renumbers - use the returned `{version}` for\n a chained edit, but re-read (`get_lesson`) before composing NEW block\n references. The user's pasted outline is also a snapshot: before a\n delete/replace, check the target block's type and content match what they\n described, not just its number.\n5. On a `stale_document` error, the lesson changed under you (usually the\n owner's own in-app edit). Re-read, re-apply your intent to the fresh\n document, and never blind-retry the same call.\n6. Consolidate. Writes share a 60/hour budget with saves, and each update\n re-renders the lesson for a watching owner - one thoughtful update beats\n five drips.\n\n## Anchoring (mandatory)\n\nThe renderer's best features - inline play chips, deep links into Listen and\nWords, listening exercises - are all opt-in through optional fields. A lesson\nthat omits them renders flat. These are hard rules, not suggestions:\n\n- **Every `vocab` entry MUST carry `position`.** The anchor is what puts an\n audio play chip on the row and a crosslink to the Words tab. A vocab entry\n with no position is a dead row.\n- **Every MCQ that tests LISTENING MUST carry `audio`** (and a `position`\n when it points at one sentence). Without `audio` it is a reading question,\n not a listening one. A pure recognition/gist MCQ before reading is the one\n case that legitimately has no audio.\n- **Every gap-fill item SHOULD carry `position` and `translation`.** The\n position anchors it to the real sentence (and lights a play chip where the\n renderer supports it); the translation gives the learner the meaning to\n work from.\n- **Dialogue highlights on the grammar pattern are required.** Every\n `dialogue` line that carries an instance of the lesson's grammar point MUST\n mark it with `highlights` (code-point ranges) so the pattern shows as gold\n marks. A dialogue with no highlights wastes the one grammar point.\n\n## The scaffold and the archetype menu\n\n**Scaffold (default skeleton, in order):** Listen -> Text -> Vocabulary ->\nGrammar -> Exercises -> Review. Use `section` blocks to head each stage; the\nrenderer numbers them. This ordering (recognition before reading, one grammar\npoint, graded practice, can-do close) is the pedagogy and holds for every\nlesson.\n\n**Archetype menu (the variety).** The Exercises stage - and the Listen and\nText stages' interactive bits - are NOT a fixed list. Pick **2-3 archetypes**\nper lesson, keyed to the grammar point, the level, and what the episode's\naudio actually affords, so consecutive lessons on the same episode don't feel\nidentical. The archetypes (recipes for the starred ones are below):\n\n| Archetype | Block(s) | Best for |\n|---|---|---|\n| Gist MCQ (no audio) | `exercise_mcq` | opening recognition, every lesson |\n| T/F comprehension * | `exercise_mcq`, 2 options | after the listen, low/mid levels |\n| Listening-detail MCQ | `exercise_mcq` + `audio` + `position` | any level, checks a specific line |\n| Minimal-pair MCQ * | `exercise_mcq` + `audio` | morphology, separable prefixes, case, tense |\n| Back-chain ladder * | 3-4 `audio_slice` | one hard/long sentence; prosody; word order |\n| Assimil passive wave * | `prose` + `dialogue` | the Text stage, every level |\n| Anticipation round * | `prose` + `audio_slice` pairs | cued recall, mid/high levels |\n| Grammar gap-fill | `exercise_gap_fill` | the grammar point itself, every lesson |\n| Vocabulary gap-fill | `exercise_gap_fill` + `wordbank` | vocabulary consolidation, low/mid |\n| Match words -> meanings | `exercise_match` | vocabulary, low/mid levels |\n| Sentence reorder * | `exercise_order` | word order / clause structure, every level |\n| Dictation * | `exercise_dictation` | native-audio dictation, listening precision |\n| Shadowing * | `exercise_shadow` | pronunciation & prosody, the differentiator |\n| Production | `exercise_production` | active use, mid/high levels |\n\n**Which archetypes for which lesson** (grammar-point type x level -> pick from):\n\n| Grammar point | A1-A2 | B1-B2 | C1+ |\n|---|---|---|---|\n| Verb morphology (Perfekt, tense) | minimal-pair MCQ, grammar gap-fill | back-chain ladder, grammar gap-fill | anticipation round, production |\n| Word order / clause structure | sentence reorder, T/F comprehension | sentence reorder, back-chain ladder | anticipation round, production |\n| Cases & endings | minimal-pair MCQ, match | grammar gap-fill, minimal-pair MCQ | production, anticipation round |\n| Separable / prefix verbs | minimal-pair MCQ, listening-detail MCQ | minimal-pair MCQ, grammar gap-fill | anticipation round, production |\n| Connectors / subordination | T/F comprehension, vocabulary gap-fill | grammar gap-fill, production | production, anticipation round |\n| Vocabulary field / functional | match, vocabulary gap-fill | listening-detail MCQ, production | anticipation round, production |\n\nAlways keep one grammar gap-fill (or minimal-pair MCQ) that drills the actual\ngrammar point, plus one vocabulary archetype; the third slot is where you\nvary. Distractors in any MCQ or word bank come from the user's own\nvocabulary, same part of speech, so wrong answers are plausible.\n\n## Recipes\n\n### Back-chain ladder (FSI backward build-up)\n\nFor the slice's hardest sentence - the longest, or the one carrying the\ngrammar pattern - build 3-4 `audio_slice` blocks that all END at the same\npoint and grow leftward, shortest first, so the learner chorus-repeats the\ntail then extends it: \"…gemacht.\" -> \"…heute gemacht.\" -> the whole sentence.\n\nComputing the windows from the sentence's transcript `start` S and `end` E\n(there are no per-word times, so estimate):\n\n- per-word duration `d = (E - S) / word_count`;\n- slice covering the last `w` words: `start = E - w*d`, `end = E`;\n- use growing `w` (e.g. last 2 words -> last 5 -> full sentence at `start=S`);\n- the END anchor `E` is exact; the estimated starts can land mid-word, so\n subtract ~0.3 s from each computed `start` (floor at S) to avoid clipping\n the first syllable.\n\nLabel each block with the words it contains, e.g. `\"Just the ending:\ngemacht.\"` then `\"…heute gemacht.\"` then the full sentence. The schema needs\n`end > start` and `start >= 0`, and every window must sit inside the source\nslice.\n\n### Assimil passive wave\n\nBefore the `dialogue` block in the Text stage, put an instruction `prose`\nthat runs the passive wave: listen once without reading, then read while\nlistening, then reveal translations line by line. The dialogue block already\nblur-reveals each line's translation, so the instruction is what makes it a\ntechnique rather than a wall of text. Example prose:\n\n> \"Listen to the scene once with the audio above, without reading. Play it\n> again and read along. Then tap each line to reveal its translation and\n> check you understood.\"\n\n### Anticipation round (Pimsleur-style)\n\nCued recall in pairs. For 3-5 target phrases from the slice, emit a `prose`\n(the L1 prompt + a one-line hint on how to say it) immediately followed by an\n`audio_slice` that plays the phrase from the real audio as the answer.\nInstruct the learner to cover the answer, say the German aloud, THEN play to\ncheck. Keep the answer slice's `label` NEUTRAL (\"Play the answer\") - printing\nthe German would spoil the anticipation. Build the answer window from the\ntarget sentence's `start`/`end` (a back-chain-style tail slice works if you\nwant just the phrase). Order the pairs from easiest to hardest.\n\n### Minimal-pair / discrimination MCQ\n\nAn `exercise_mcq` with a tight `audio` window over the contrasting word or\nphrase, and options that differ in exactly ONE morpheme - perfect for German\nseparable prefixes (`steht auf` vs `versteht`), case endings (`dem` vs\n`den`), or tense/participle (`gefahren` vs `fahren`). `correct` indexes the\nform actually spoken; the distractors are real minimal variants, not\nnonsense. Add `position` so the row deep-links to the sentence.\n\n### T/F comprehension\n\nAn `exercise_mcq` with exactly TWO options - `[\"Richtig\", \"Falsch\"]` (or the\nlearner's language at A1/A2) - and a `prompt` that states something about the\npassage. Place 2-3 of them after the Listen section. Add `audio` + `position`\nto make it a listening check rather than a reading one.\n\n### Sentence reorder (Satzbau)\n\nAn `exercise_order` with 1-5 `items`, each a sentence broken into `segments`\n(3-12 chunks) IN CORRECT ORDER - the renderer scrambles them; the learner\nreassembles. This is the right tool whenever the grammar point is word order\nor clause structure (verb-second, verb-final in subordinate clauses,\nseparable-prefix placement): it supersedes an ad-hoc gap-fill where a real\nscramble fits. Anchor each item to its sentence with `position` and the server\nchecks the segments reassemble the stored sentence (whitespace-insensitive),\nrejecting a drifted scramble with `order_mismatch`; so quote the real chunks,\ndo not paraphrase. Split at meaningful units (a chunk can be a word or a short\nphrase like \"am Wochenende\"), and add `translation` so the learner has the\nmeaning to aim for.\n\n### Dictation (Diktat)\n\nAn `exercise_dictation` with 1-5 `items`, each anchoring a stored sentence by\n`position` (REQUIRED). The app plays that sentence's native audio and diffs the\nlearner's typing against the LIVE transcript word by word - nothing is copied\ninto the document, so the answer stays truthful as the transcript is edited.\nPick 2-4 SHORT, clearly-articulated sentences (dictation of a long or mumbled\nline just frustrates); optionally set a wider `audio` window to include a beat\nof lead-in, keeping it COVERING the sentence. Add `translation` for the meaning.\n\n### Shadowing (the differentiator)\n\nAn `exercise_shadow` with 1-8 `items`, each a stored sentence by `position`\n(REQUIRED) - the app plays the native line, records the learner, and replays\ntheir take (in-memory only, no upload, no score - self-assessed). This is the\nproduct's core practice move inline in a lesson; use it to make a lesson end in\nreal speaking. Pick 3-8 of the dialogue's best lines - the ones worth being\nable to say fluently - in the order they occur. Add `translation` per line.\n\n## The lesson.v1 document (quick reference)\n\nTop level: `{format:\"lesson.v1\", title, subtitle?, language,\ntranslation_language, level?, source:{submission_id, from_time?, to_time?,\nepisode_title?}, generator?:{skill, version?}, objectives?[<=5],\nestimated_minutes?, blocks[<=40]}`.\n\nBlocks (`type` field): `section {title, subtitle?}` · `prose {text,\nstyle:\"instruction\"|\"body\"}` · `audio_slice {audio:{start,end}, label?}` ·\n`dialogue {lines:[{position, speaker?, text, translation?,\nhighlights?:[[start,end],...]}]}` · `vocab {entries:[{lemma, pos?, display?,\nforms?, meaning, cefr?, position?}]}` · `grammar_box {title, explanation,\nevidence:[{position?, text, note}], merke?, achtung?}` · `exercise_mcq\n{title?, instruction?, prompt?, audio?, position?, options[2..5],\ncorrect:0-based index}` · `exercise_gap_fill {title?, instruction?, wordbank?,\nitems:[{position?, text, answers:[[alternatives],...], translation?}]}`\n(gaps are `{{1}}`, `{{2}}`, ... in `text`; `answers[n-1]` lists accepted\nalternatives for gap n) · `exercise_match {title?, instruction?,\npairs:[{left,right}][2..8]}` · `exercise_order {title?, instruction?,\nitems:[{position?, segments[3..12] in correct order, translation?}][1..5]}`\n(segments must reassemble the anchored sentence) · `exercise_dictation\n{title?, instruction?, items:[{position (REQUIRED), audio?:{start,end},\ntranslation?}][1..5]}` · `exercise_shadow {title?, instruction?,\nitems:[{position (REQUIRED), translation?}][1..8]}` · `exercise_production\n{title?, instruction?, prompt, model_answer}` · `review {can_do?[<=5],\nnew_lemmas?[<=12]}`.\n\n`position?` in the reference is the SCHEMA shape (optional); the Anchoring\nsection is where authoring policy makes some of these anchors mandatory.\n\n**Text formatting.** `prose.text` and `grammar_box.explanation` render a\nmini-Markdown subset in the app: `**bold**`, `*italic*`, backtick code,\n`- `/`* ` bullet lines, and blank-line paragraph breaks. Exercise\n`instruction` fields and `grammar_box.merke`/`achtung` render the inline\nmarks only (no bullets or paragraphs). Every other text field (titles,\nprompts, options, vocab meanings, dialogue lines) is plain text. Headings,\nlinks, tables, images and raw HTML are never rendered anywhere - they show\nas literal characters, so don't emit them.\n\nCaps: 40 blocks, 30 dialogue lines, 20 vocab entries, 5 MCQ options, 10\ngap-fill items, 8 match pairs, 5 order items (3-12 segments each), 5 dictation\nitems, 8 shadow items, 8 highlight spans per line, 1 MB serialized.\n\nThe server is the validator of record (strict: unknown fields and block\ntypes are rejected). Audio is `[start,end)` seconds into the ORIGINAL\nepisode audio - never generate, clip or embed audio files.\n\n## Hard rules\n\n- **Ground, do not invent.** Every dialogue line quotes the transcript\n verbatim by `position`; meanings, genders and CEFR come from\n `lookup_word`/`get_vocabulary`. The server enforces the quoting.\n- **Anchor everything (see Anchoring above).** Vocab entries carry\n `position`; listening MCQs carry `audio`; gap-fill items carry `position`\n and `translation`; grammar-pattern dialogue lines carry `highlights`. An\n unanchored lesson renders flat and is a bug.\n- **LingoChunk is the system of record for word knowledge.** Do not drill a\n `known` word unless it is also `due`. Never write review grades back.\n- **One grammar point per lesson.** Depth beats coverage; a second point is\n a second lesson.\n- **Vary the archetypes.** Pick 2-3 from the menu keyed to the grammar point\n and level; do not emit the same fixed exercise list every time.\n- **Respect the source.** Only use content the tools return; put the\n episode title in `source.episode_title`.\n- **No audio handling.** The app plays ranges of the original audio;\n `get_audio_clip` is NOT part of this workflow. `audio_slice` windows are\n built from transcript sentence `start`/`end` times.",
|
|
18
|
+
},
|
|
19
|
+
"course": {
|
|
20
|
+
topic: "course",
|
|
21
|
+
promptName: "lingochunk-course",
|
|
22
|
+
description: "Plan a multi-lesson course from one of the user's own LingoChunk episodes or a collection - a named, ordered series where each lesson covers a different grammar point and ramps in difficulty, built with the lingochunk-lesson flow and filed under a course. Use when the user asks for a course, a series, a multi-part study plan, \"a whole set of lessons\", or \"break this episode into a course\".",
|
|
23
|
+
body: "# LingoChunk course planner\n\nTurn one rich episode (or a collection) into a coherent SERIES of lessons: a\nnamed `course` with N ordered lessons, each a self-contained `lingochunk-lesson`\ndocument with a DIFFERENT grammar point and a difficulty that ramps across the\nseries. LingoChunk supplies the materials (transcripts with positions and\ntranslations, FSRS-graded vocabulary) and renders every lesson natively; your\njob is the arc - how to slice the source, what each lesson teaches, and in what\norder - and then to drive the existing lesson flow once per slice.\n\nThis skill uses the `lingochunk` MCP tools. If they are not available, tell the\nuser to add the LingoChunk MCP server (see the plugin README) and stop. This\nskill ORCHESTRATES `lingochunk-lesson`: read that guide (`get_authoring_guide`\nwith `topic='lesson'`) before composing any single lesson - this one only adds\nthe multi-lesson planning on top.\n\n## When to use\n\n- \"Make a course out of this episode.\"\n- \"Build me a series of lessons on the B1 podcast, one per scene.\"\n- \"Break this 20-minute episode into a study plan I can work through.\"\n- \"Turn this collection into a beginner course.\"\n\n## Options to settle first (ask only what the user left open)\n\n1. **Source**: one episode (`list_library`), or a collection you slice\n episode by episode. A single lesson has ONE source episode in v1, so each\n lesson in the course draws from one episode (or one slice of it).\n2. **Length**: how many lessons. Default to what the material honestly\n supports - a 3-8 minute slice per lesson, so a 20-minute episode is ~3-5\n lessons, not fifteen thin ones. Say the number you chose and why.\n3. **Level and ramp**: the starting CEFR level and whether it climbs. Infer\n the floor from the CEFR mix of `get_vocabulary(status=known)` if the user\n does not say. State the ramp (e.g. \"A2 for lessons 1-2, B1 for 3-4\").\n\n## Workflow\n\n1. **Inventory the source.** `list_library` to find the episode(s). For each,\n pull the shape: `get_transcript` (sentence positions, timings, speakers) and\n `get_vocabulary` (what is known vs learning/new/due). You are looking for\n natural seams - scene changes, topic shifts, a run of sentences that share a\n grammar pattern - and for which grammar points the material can actually\n evidence.\n2. **Split into coherent slices.** Carve the source into N slices, each a\n 3-8 minute span that stands on its own AND carries enough evidence for one\n grammar point. Prefer seams the audio already has (a new scene, a new\n speaker turn) over arbitrary time cuts. Write down, per slice: its\n `from_time`/`to_time`, its ONE grammar point, its level, and 2-3 archetypes\n from the lesson skill's menu - deliberately varying the archetype mix across\n slices so consecutive lessons do not feel identical.\n3. **Ramp the difficulty.** Order the slices so difficulty climbs: earlier\n lessons lean on recognition (MCQ, matching, sentence reorder) and lower-level\n grammar; later lessons lean on recall and production (dictation, shadowing,\n gap-fill, production) and harder points. No grammar point repeats across the\n course - depth over coverage, one point per lesson, a different point each\n lesson.\n4. **Create the course.** `create_course` with a `title` and a short\n `description` naming the arc. Keep its `id`.\n5. **Build the lessons in order.** For each slice, run the full\n `lingochunk-lesson` flow (pull the slice, filter vocabulary, pick the ONE\n grammar point you assigned it, compose on the scaffold with its archetypes).\n Before each save, call `validate_lesson` with `{document}` and fix EVERY\n problem it reports; only once it returns `valid: true` do you `save_lesson`\n with `{document, course_id, sequence}` - `sequence` = the lesson's 1-based\n position in the course (ties break by created_at, but pass explicit\n sequences so the order is deliberate). Stamp\n `generator: {skill: \"lingochunk-lesson\"}` on each document.\n6. **Deliver.** List the course and its lessons in order (title, level, grammar\n point, `app_url`), so the user can work through them as a series. Offer\n `add_card` for the drill words the course introduced. Confirm the course\n groups them: `list_lessons` echoes each lesson's `course_id`, `sequence` and\n `course_title`.\n\n## Hard rules\n\n- **Delegate the pedagogy.** Every single lesson obeys the `lingochunk-lesson`\n rules (anchoring, verbatim quoting, one grammar point, archetype variety).\n This skill only decides the arc; it does not relax any lesson-level rule.\n- **A different grammar point per lesson.** The point of a course is breadth\n across lessons and depth within each; never repeat a grammar point.\n- **Ramp, do not flatten.** Order lessons by increasing difficulty; do not\n emit N interchangeable lessons at one level.\n- **Validate before every save.** Call `validate_lesson` and reach\n `valid: true` before `save_lesson`, for each lesson in the course.\n- **Ground, do not invent.** Quoted lines come from the transcript by\n `position`; meanings, genders and CEFR come from the tools. Only use content\n the tools return; the user's data never goes to any other service.\n- **No audio handling.** Reference `[start, end)` windows of the original\n episode audio; never generate, cut or embed audio. Deleting a course only\n un-groups its lessons - it never deletes them.",
|
|
24
|
+
},
|
|
25
|
+
"cards": {
|
|
26
|
+
topic: "cards",
|
|
27
|
+
promptName: "lingochunk-cards",
|
|
28
|
+
description: "Create native-grade flashcards in the user's LingoChunk deck from real episode content via the card.v1 add_card kinds (word, phrase, collocation, idiom, chunk, grammar, cloze, contrast, qa, production). Anchors every card to a verbatim transcript sentence so the server can paint the highlight/blur and cut native speaker audio. Use when the user asks to make flashcards or Anki cards from an episode, add vocabulary or grammar drills to their deck, or turn a transcript passage into study cards.",
|
|
29
|
+
body: "# LingoChunk card builder\n\nCreate cards that look exactly like the app's own: real sentence, target\nhighlighted or blurred, native speaker audio, forward+reverse pairs. The\ndivision of labour: **you choose what to teach and write the glosses;\nLingoChunk verifies the anchors and derives everything visual/audible.**\n\nThis skill uses the `lingochunk` MCP tools. If they are not available, tell\nthe user to add the LingoChunk MCP server (see the plugin README) and stop.\n\n## The one rule that matters\n\n**Every span you send must be copied VERBATIM from the transcript.** Fetch\nthe sentence with `get_transcript` first; `focus_span` must be the exact\nsurface form as spoken (\"habe\", not \"haben\"; \"einem\", not \"ein\"). The server\nrejects non-verbatim spans on answer-hiding kinds\n(`code=focus_span_not_verbatim`) because a paraphrased example breaks both\nthe blur painting and the audio alignment. Never invent or \"improve\" an\nexample sentence; if the episode has no good sentence for an item, skip the\nitem and say so.\n\n## Workflow\n\n1. `get_transcript` for the episode (slice by time range if the user named\n one). Note each sentence's `position` - that is your anchor.\n2. Pick targets. One card = one thing to learn. Prefer items the sentence\n demonstrates naturally.\n3. `add_card` per item with a card.v1 kind (below). Include `note` (one-line\n why), `hint` (only when the answer has competing valid fills), `cefr`\n when you are confident.\n4. **Read the response.** `problems[]` lists degradations\n (`focus_span_no_timings`, `context_position_unknown`, ...). Fix what you\n can and resend - the same headword updates in place (`created: false`),\n so a correction never duplicates a card.\n5. Report to the user what was added, kind by kind, and anything skipped.\n\n## Choosing a kind\n\n| Kind | Use for | Front shows |\n|---|---|---|\n| `word` | one new word (include the article: \"die Landschaft\") | headword hero + example with the word highlighted |\n| `phrase` / `idiom` / `collocation` | multi-word units, fixed combinations | same, multi-word headword |\n| `chunk` | a whole useful sentence/utterance | the chunk as headword |\n| `grammar` | a form choice the sentence demonstrates (case ending, article, verb form, word order) | example with the morpheme blurred + \"why\" slot |\n| `cloze` | recall one content word in context | example with the word blurred |\n| `contrast` | 2-3 confusables (wissen/kennen) | option chips + gap in the example |\n| `qa` | an explanation with no single gap | the question as prose |\n| `production` | meaning → produce the target phrase | the gloss as prompt, target blurred |\n\nLexical kinds (word/phrase/collocation/idiom/chunk) create a\nforward+reverse pair and get a native-audio clip of the focus span; pass\n`direction: \"forward\"` if the user only wants recognition. Study kinds are\nforward-only by design.\n\n## Grammar cards done right (the reason this skill exists)\n\nBlur the **morpheme, not the clause**: for \"Wir wohnen in einem Haus\", the\nfocus span is `einem`, the translation slot carries the why (\"dative after\n'in' for location\"), and the note adds the one-line rule. Give a `hint` when\nseveral fills are grammatical (\"dative\", \"past participle\"). Do NOT make\nrule-memorisation cards (\"What are the dative prepositions?\") - route the\nrule through a real sentence, or use `qa` sparingly for a genuine\nexplanation the user asked about.\n\n## Quality rubric (check every card before sending)\n\nDistilled from the failure modes that make AI-generated cards unusable:\n\n- **Unambiguous**: exactly one thing is being asked; the front cannot be\n answered two valid ways without a hint.\n- **One target**: a card never teaches two words or two rules at once.\n- **Grounded**: example is verbatim from THIS episode; never a made-up\n sentence.\n- **Short slots**: translation ≤ a phrase, note ≤ one line. No wall-of-text\n backs; if you need a paragraph, it is a `qa` card or not a card at all.\n- **Self-contained**: the card makes sense months later without the chat\n context.\n- **Not context-cheatable**: for cloze/grammar, the sentence should not spell\n out the answer elsewhere.\n\n## Don'ts\n\n- Don't paraphrase transcript sentences (see the one rule).\n- Don't batch dozens of cards uninvited - propose, let the user choose, or\n follow their stated scope.\n- Don't use legacy `kind=custom` when a card.v1 kind fits; flat front/back\n cards render without highlight, audio window, or per-kind chrome.\n- Don't retry a `409 duplicate_card` (legacy kinds) or resend unchanged\n bodies to clear `problems` that need different input.\n- Don't add reverse pairs for study kinds - the server ignores it and tells\n you (`direction_ignored`).",
|
|
30
|
+
},
|
|
31
|
+
"annotations": {
|
|
32
|
+
topic: "annotations",
|
|
33
|
+
promptName: "lingochunk-annotate",
|
|
34
|
+
description: "Find the genuinely useful expressions in one of the user's own LingoChunk episodes (idioms, phrasal verbs, collocations, discourse markers, culture-bound references) and attach a short markdown creator note to each exact span. Owners see the note as a tint + bottom sheet on the Listen tab; followers get it as a forward-only note card. Use when the user asks to find or annotate useful expressions in an episode, highlight idioms or phrases, or add creator notes to a lesson.",
|
|
35
|
+
body: "# LingoChunk expression annotator\n\nRead one of the creator's own episodes and mark the expressions a learner\ngenuinely cannot decode word by word, attaching a short markdown note to each.\nLingoChunk keeps the transcript, timings and word analysis; the only work here is\njudgement (which spans are worth a note) and writing (a tight explanation for the\ncreator's students). The app renders every note natively: the owner sees an\niris tint on the span plus the note in a bottom sheet, and followers of the\ncollection get the note as a forward-only card. No new audio, no UI to build.\n\nThis skill uses the `lingochunk` MCP tools. If they are not available, tell the\nuser to add the LingoChunk MCP server (see the plugin README) and stop.\n\n## When to use\n\n- \"Find the useful expressions in this episode and annotate them.\"\n- \"Highlight the idioms and phrasal verbs in episode X.\"\n- \"Add creator notes to my lesson so my students get the phrasing, not just the\n words.\"\n- \"Go through this recording and explain the fixed phrases.\"\n\n## Who and what this is for\n\n- **Owner + creator tier only.** Every annotation endpoint is owner-scoped; an\n episode the user does not own is a 404. Creating notes needs the\n `annotations:write` scope (edit-transcripts feature); reading needs\n `content:read`. The user's data never goes to any other service.\n- **Write for the students, not the creator.** These notes become follower\n cards and the owner's own study sheet. Pitch them as if teaching a learner who\n is a level below the episode's audience, not as notes-to-self.\n\n## What counts as a useful expression (annotate these)\n\nAnnotate a span only when a learner who knows the individual words would still\nmiss the meaning:\n\n- **Idioms and figurative phrases** (\"den Ball flach halten\", \"hit the nail on\n the head\").\n- **Phrasal verbs whose meaning is not the sum of the parts** (\"give up\",\n \"auf jemanden zugehen\").\n- **Strong collocations and fixed phrases** the learner should learn as a unit\n (\"make a decision\" not \"do a decision\"; \"eine Entscheidung treffen\").\n- **Discourse markers and fillers doing real conversational work** (\"doch\",\n \"na ja\", \"I mean\", \"you know\") - the ones that steer the turn, not literal\n content.\n- **Culture-bound references** a learner cannot look up word by word (a TV show,\n an institution, a local custom named in passing).\n\n## What does NOT count (skip these)\n\n- **Ordinary single words.** The vocabulary deck already covers them; a note per\n hard word is clutter. Annotate a word only when it is part of a larger\n non-transparent expression.\n- **Proper names** (people, places, brands) with no idiomatic twist.\n- **Anything transparent** - a phrase whose meaning is exactly its words. If the\n student can decode it from the words plus the sentence translation, leave it.\n\n## Density: quality over coverage\n\n- **Typically 15 to 40 notes per episode.** That is enough to catch the phrasing\n a learner would trip on without burying the transcript in tint.\n- **Check the budget first.** `list_annotations` returns `count` and\n `max_annotations` (the per-episode cap). Never carpet-bomb toward the cap;\n a note on every other line is noise, and once you are near the cap the creator\n cannot add their own.\n- **Do not re-annotate.** Read the existing notes first (`list_annotations`) and\n skip expressions that already have one.\n- **Annotate a recurring expression once.** If the same idiom appears several\n times, annotate the clearest instance and say \"appears several times in this\n episode\" in the note, rather than tinting every occurrence.\n\n## Workflow\n\n1. **See what exists and your budget.** `list_annotations(submission_id)`. Note\n `count` vs `max_annotations`, and read the existing notes' `selected_text` so\n you do not duplicate them. A note with `stale: true` was left dangling by a\n later transcript edit - offer to replace or `delete_annotation` it.\n2. **Pull the transcript.** `get_transcript(submission_id, ...)` (slice by\n sentence or time range for a long episode). Only `transcript_state: \"ready\"`\n is usable. Each sentence carries a stable `sentence_id` and its `display`\n string - both are what you anchor to.\n3. **Select the expressions** worth a note using the rules above. Prefer depth\n over breadth: the twenty phrases a learner would actually stumble on beat\n forty obvious ones.\n4. **Anchor each one.** For every expression, compute the **code-point offsets**\n of the EXACT span inside that sentence's `display`:\n - Offsets are Unicode code points (Python string semantics), NOT UTF-16\n units. In JavaScript, `[...display].slice(start, end).join(\"\")` counts code\n points correctly; `display.slice(start, end)` / `indexOf` do NOT beyond the\n BMP (an emoji or some rare CJK counts as 1 code point but 2 UTF-16 units).\n - Prefer the **tightest span** that covers the expression (just \"den Ball\n flach\", not the whole clause). Use a **whole-sentence note** (omit\n `char_start`/`char_end`) only when the entire line IS the expression.\n5. **Create it.** `create_annotation(submission_id, sentence_id, char_start,\n char_end, note)`. Leave `start_time`/`end_time` unset: the server derives\n the span's audio times from the transcript's word timings, so the note\n sheet's Play button and the deck-card clip work without them.\n6. **Verify the span.** The response echoes `selected_text` =\n `display[char_start:char_end]`. Check it equals the expression you meant. On a\n mismatch your offsets were off (usually a UTF-16 vs code-point miscount):\n `delete_annotation` that note and create it again with corrected offsets. Do\n not leave a note on the wrong span.\n7. **Deliver.** Tell the user how many notes you added and what they cover, and\n remind them the notes are live for the owner (tint + sheet on Listen) and for\n followers (forward-only note cards).\n\nTo reword a note without moving it, use `update_annotation` (note only). To\nmove a span, `delete_annotation` and create it again.\n\n## Note format\n\nThe note is markdown (up to 5000 chars, but keep it to **~4 short lines** - it\nrenders in a bottom sheet, not an essay). Use this shape:\n\n```\n**<the expression>** - <register tag, e.g. informal, British, formal>\n<one plain-language line: what it means>\nHere: <how it is used in THIS sentence>\nExample: <one fresh sentence using the expression naturally>\n```\n\nOptionally add a fifth line on close variants (\"also heard as ...\") when it\nhelps. Keep each line short. Write the meaning line so a learner a level below\nthe episode's audience understands it - no jargon, no re-using the hard word to\nexplain itself.\n\nExample (a German B1 episode):\n\n```\n**den Ball flach halten** - informal\nto keep things calm; not take a risk or make a fuss\nHere: he is telling the team not to overreact to the news.\nExample: Bleib ruhig und halt den Ball flach, bis wir mehr wissen.\n```\n\n## Language\n\n- **Default to the episode's own language**, in a simpler register - roughly one\n CEFR level below the lesson's audience. A B1 episode gets notes a strong A2\n learner can read. This keeps the student inside the target language.\n- **Override to the learner's native language** only when the user asks for it\n (e.g. \"explain them in English for my beginners\"). Then write the whole note\n in that language.\n\n## Hard rules\n\n- **Ground, do not invent.** Annotate expressions that actually occur in the\n transcript the tools return; take the meaning from the sentence and its\n translation. Never attribute phrasing the recording does not contain.\n- **Tightest real span.** Anchor the expression itself, not the surrounding\n clause; whole-sentence notes are for lines that are entirely the expression.\n- **Verify every span.** Always check the returned `selected_text`; fix a\n mismatch with delete + recreate before moving on.\n- **Budget, do not flood.** Stay in the 15 to 40 range, well under\n `max_annotations`; skip words the vocabulary deck already carries.\n- **Only the user's own episodes.** Owner-scoped; a foreign submission is a 404.\n- **No audio handling.** The note anchors to text; the server derives the\n audio span from the transcript, so never send times yourself.",
|
|
36
|
+
},
|
|
37
|
+
"add-language": {
|
|
38
|
+
topic: "add-language",
|
|
39
|
+
promptName: "lingochunk-add-language",
|
|
40
|
+
description: "Add another language to one of the user's own LingoChunk episodes so it becomes a new sibling deck. Two paths: trigger the server-side fan-out for an ordinary target language (Groq, spends no tokens), or translate the episode yourself sentence by sentence and commit it - the only way to build a leveled same-language deck (e.g. \"German (A2)\": German audio glossed in simpler A2 German). Use when the user asks to add a language or translation to an episode, translate a lesson into another language, or make a simplified same-language (A1-B2) version of an episode.",
|
|
41
|
+
body: "# LingoChunk add-language builder\n\nAdd a target language to one of the learner's own episodes. LingoChunk keeps a\nsubmission's audio, timestamps and word analysis and reuses them across\nlanguages; the ONLY per-language work is the translation surface (the\nwhole-sentence translation plus one meaning per word). This skill drives that\nwork two ways:\n\n- **Ordinary target language, on the house.** `add_language` triggers the\n server's Groq fan-out. No tokens of yours, no per-word work - you hand it\n language codes and poll for the new siblings.\n- **Agent-supplied translation, on your tokens.** You page through the\n episode's sentences, translate them yourself, draft them in batches and\n commit. This is the only path that produces a **leveled same-language\n deck** (`en-a2`, `de-b1`, ...): the audio stays the source language and the\n \"translation\" is a SIMPLER register of that same language, for levelling up\n within a language you already read.\n\nThe division of labour is the point: LingoChunk supplies the source material\nand mints the sibling; you supply the translation on the user's own tokens.\nNothing here spends server LLM budget on the draft path.\n\nThis skill uses the `lingochunk` MCP tools. If they are not available, tell the\nuser to add the LingoChunk MCP server (see the plugin README) and stop.\n\n## When to use\n\n- \"Add French and Ukrainian to this episode.\"\n- \"Translate my German episode into Polish.\"\n- \"Make a simplified German (A2) version of this episode so I can level up.\"\n- \"Add an English-glossed-in-simple-English deck to this recording.\"\n\n## Pick the path first (ask only what the user left open)\n\n1. **Which submission.** A named episode, or `list_library` to find one. Only\n the READY primary of a group is a valid source; a derived sibling is not.\n2. **Which language(s).** Run `list_languages(submission_id)` and read:\n - `available_targets` - ordinary languages you may fan out with\n `add_language`.\n - `simplify_targets` - leveled same-language codes (only those whose base\n equals the source language; `de-a2` appears on a German episode, not on a\n French one). These go through the DRAFT path only.\n - `languages` - what already exists (skip these); `drafts` - work in\n progress you can resume.\n3. **Which path.**\n - Ordinary target and the user is happy with the built-in translation ->\n **fan-out path** (`add_language`). Fastest, no tokens.\n - A leveled code, OR an ordinary target the user wants YOU to translate ->\n **draft path** (translate + commit). Leveled codes are rejected by\n `add_language`, so they always take the draft path.\n4. **For a leveled code, which level.** The code carries it (`de-a1` .. `de-b2`).\n If the user says \"simple German\" without a level, default to `a2` and say so.\n\n## Fan-out path (ordinary targets, server-side)\n\n1. `add_language(submission_id, languages)` with 1-10 codes from\n `available_targets`. It returns a `job` per accepted language and a\n `skipped` list (source language, an existing sibling, or a leveled code with\n reason `agent_only_target`).\n2. Poll `list_languages` until each new sibling's `status` is `ready`. Report\n the ready siblings; a `skipped` leveled code means \"use the draft path\".\n\n## Draft path (you translate; ordinary target OR leveled same-language)\n\n1. **Page the source.** `get_translation_source(submission_id, from_position,\n limit)`. Each sentence gives `text`, `pivot_translation` (the whole sentence\n in the pivot language) and `tokens` - `surface`, `lemma`, `pos` and a\n `pivot_meaning` that FIXES each word's sense (which homonym, which reading).\n Follow `next_from_position` until it is null. Note `pivot_language` and\n `source_language` from the response.\n2. **Translate in batches of 25-50 sentences.** Produce, per sentence:\n - `meanings`: one entry per token, **same order, exact same length as\n `tokens`** (count them). Rules below.\n - `translation`: the whole-sentence line (rules below), or `null`.\n Trust the `pivot_meaning` for each word's sense - it came from a strong\n model with the full context. Do not re-interpret the word.\n3. **Upload.** `put_language_translations(submission_id, language, generator,\n sentences)` (1-100 per call). Set `generator` to your model id. The server\n validates each sentence against the real transcript and returns a `rejected`\n list while ACCEPTING the rest - common reasons: `meanings_length_mismatch`\n (it names `expected`/`got`; you miscounted the tokens), an unknown\n `position`, an oversize string. Fix only the rejected sentences and PUT them\n again. Keep a **local tally of every position you have covered**.\n4. **Commit.** `commit_language(submission_id, language)` when the tally covers\n every sentence. A 409 means the draft is incomplete - it lists the missing\n count and the first missing positions; PUT those, then commit again. The\n tool starts the apply job and polls it: `status:'completed'` returns the new\n sibling's `submission_id`; `status:'processing'` means call `list_languages`\n shortly to see it appear.\n5. **Deliver.** Tell the user the sibling is ready and how it is labelled\n (e.g. \"German (A2)\"). To abandon a half-finished draft, use\n `discard_language_draft` (it removes only the draft rows, never a committed\n sibling).\n\n## Ordinary-target translation rules\n\nFor a real other-language deck (source -> target, e.g. German -> Polish):\n\n- **`meanings`**: the target-language dictionary base form of each word in the\n sense the `pivot_meaning` fixes (NOUN singular, VERB infinitive, ADJ/ADV\n base). One per token, same order, exact length.\n- **PUNCT and INTJ/filler tokens -> `\"\"`.** Never omit the final full stop's\n entry and never add extra entries - that is an off-by-one on every sentence.\n- **Proper nouns -> the name itself.**\n- **Never copy the pivot or source word verbatim** as its meaning; render it in\n the target language.\n- **`translation`**: a fluent, natural whole-sentence translation of the source\n sentence into the target language.\n\n## Leveled same-language rules (`en-a2`, `de-b1`, ...)\n\nPorted from LingoChunk's validated simplification prompt. Here the audio and the\noutput are the SAME language; you are writing a monolingual learner-dictionary\ngloss in a simpler register. The code's level sets the bar: `a1` = the ~500 most\nbasic everyday words; `a2` = basic everyday vocabulary; `b1` = intermediate;\n`b2` = upper-intermediate. When unsure, go simpler.\n\n**`meanings` - per word, decide first: does a learner AT THE TARGET LEVEL know\nthis word?** Everyday words (family, food, home, school, common actions,\nfunction words) - yes at every level. Formal, administrative, legal, literary,\nacademic, technical and news-register words - no, even when they are frequent in\nnewspapers.\n\n- **Word at or below the target level -> gloss it as its own dictionary base\n form.** An easy word is its own meaning. Never expand an easy word into a\n definition (\"dog\" stays \"dog\", never \"animal that barks\"). At `b1`/`b2` this\n means most words pass through unchanged, and you only simplify the genuinely\n harder ones; at `a1`/`a2` far fewer words survive as themselves.\n- **Word above the target level -> write something DIFFERENT and EASIER**: an\n everyday same-language synonym, or a short plain 2-4 word phrase with the same\n meaning in this sentence. Examples: \"committee\" -> \"group\", \"endeavoured\" ->\n \"tried\", \"obtain\" -> \"get\", \"inquire\" -> \"ask\".\n - **Anti-echo (the main failure mode):** repeating the word, or its base\n form, is a WRONG answer for a hard word. \"obtain\" -> \"obtain\" is wrong.\n - **Formal-synonym trap:** a replacement that is just as rare or formal is\n also WRONG - pick the word a beginner would actually know. Every word inside\n your meaning must itself be an everyday word.\n - **Administrative, legal and institutional vocabulary** (courts, ministries,\n regulations, committees, contracts, official procedures) is NEVER beginner\n vocabulary, in any language - always give it an everyday replacement, even\n when it is common in the news.\n - If you are unsure whether a word is known at the level, treat it as unknown\n and simplify it.\n- Keep the sense fixed by the `pivot_meaning` (the water sense of a word, not\n the electricity sense). Everything you write is in the SOURCE language; never\n let a pivot-language word into the output. PUNCT/INTJ -> `\"\"`; proper nouns ->\n the name.\n- Before finalising a sentence, re-check: any meaning identical to its input\n word must really be everyday vocabulary at the level; if it is formal,\n official or literary, replace it with an easier one.\n\n**`translation` - a simplified rewrite of the whole sentence in the same\nlanguage**, ONLY where a genuinely simpler phrasing exists:\n\n- Everyday spoken vocabulary, short main clauses, active voice, the most basic\n tenses that keep the meaning. Replace formal/administrative/literary words\n with everyday ones. Keep ALL the information; it may be longer or split into\n two sentences. A learner at the level must understand it.\n- **Idioms and figurative phrases -> rewrite by MEANING** (the `pivot_meaning`\n shows the real meaning). Do not reuse the figurative phrase or its images: if\n it says someone \"hit the nail on the head\", write that they said exactly the\n right thing - no nail, no head.\n- **Hide-on-fail:** if the sentence is already simple and literal at the level,\n or you cannot simplify it without risking a grammar mistake or drifting from\n the meaning, send `translation: null`. A missing line is invisible; a wrong or\n un-simplified line is not. Correctness beats simplicity - never ship an\n ungrammatical or meaning-changed rewrite just to fill the field.\n\n## Optional enrichment\n\nCultural references, extended usage notes and full idiom explanations do not fit\nthe card fields (meanings are short; the sentence line is a single rewrite). If\nthe user wants that depth, offer to build a companion lesson with the\n`lingochunk-lesson` skill / `save_lesson` on the same episode - it renders\nnatively alongside the deck.\n\n## Hard rules\n\n- **Ground, do not invent.** Translate the sentences the tools return; take each\n word's sense from its `pivot_meaning`. Never invent words the sentence does\n not contain or attribute content to the recording.\n- **One meaning per token, same order, exact length.** A length mismatch is\n rejected per sentence - count the tokens (including the ones that map to\n `\"\"`).\n- **Leveled output stays monolingual.** For `en-a2`, `de-b1`, ... every meaning\n and every sentence line is in the source language; never leak the pivot\n language onto a card. Empty leveled sentence -> `null`, never the source or\n pivot sentence.\n- **Leveled codes are draft-only.** `add_language` rejects them\n (`agent_only_target`); build them with the draft path.\n- **Only the user's own episodes.** Every endpoint is owner-scoped; a submission\n you do not own is a 404. The user's data never goes to any other service.\n- **No audio handling.** The sibling reuses the primary's audio and timings\n untouched; you only supply text.",
|
|
42
|
+
},
|
|
43
|
+
"discuss": {
|
|
44
|
+
topic: "discuss",
|
|
45
|
+
promptName: "lingochunk-discuss",
|
|
46
|
+
description: "Talk through a LingoChunk episode with the learner. Fetch a slice of a real episode's transcript, discuss it in the target and native language, explain grammar and vocabulary as they come up, and look words up on demand grounded in the user's own data. Use when the user wants to discuss, talk about, go through, or be quizzed casually on one of their LingoChunk episodes, rather than generating a formal lesson artefact.",
|
|
47
|
+
body: "# Discuss an episode\n\nA lightweight companion to `lingochunk-lesson`. Where that skill produces a\nself-contained HTML file, this one is a conversation: sit with the learner and\nwork through a real episode from their LingoChunk library, using the tools to\nstay grounded in their own content instead of inventing material.\n\nUses the `lingochunk` MCP tools. If they are not available, tell the user to add\nthe LingoChunk MCP server (see the plugin README) and stop.\n\n## When to use\n\n- \"Let's discuss the second half of yesterday's episode.\"\n- \"Talk me through this German dialogue.\"\n- \"Go through episode X with me and explain the tricky bits.\"\n\n## Workflow\n\n1. **Find the episode.** If the user named it, resolve with `list_library`\n (match on title). Confirm which part they want (a sentence range or a time\n window), so you fetch a slice, not a 45-minute transcript.\n\n2. **Fetch the slice.** `get_transcript(submission_id, from_sentence/to_sentence\n or from_time/to_time)`. Check `transcript_state`: only `ready` has content.\n\n3. **Work through it.** Go sentence by sentence (or in small groups):\n - Show the target-language sentence and its translation.\n - Explain the grammar and any idioms in plain language.\n - When a word matters, call `lookup_word` for its meaning, gender and CEFR,\n and mention whether the user is already learning it (from `get_vocabulary`)\n rather than guessing. Prioritise `learning`/`new` words; do not dwell on\n words `get_vocabulary(status=known)` shows they have mastered.\n - Offer to play a bit: `get_audio_url` streams the passage (always\n available). On a local/plugin setup only, `get_audio_clip` can save a\n short snippet to disk - skip it if the tool is not offered (remote\n clients do not have it).\n\n4. **Follow the learner.** Answer their questions, look up more words on demand,\n pull related examples with `search_examples(lemma=...)` when they ask \"where\n else does this word come up\". Keep it conversational.\n\n## Rules\n\n- **Ground, do not invent.** Sentences and timestamps come from `get_transcript`;\n word facts from `lookup_word` / `get_vocabulary`. Do not make up example\n sentences - use `search_examples` for real ones from the user's library.\n- **Do not write anything back.** This is a read-only conversation; there is no\n tool to record progress, and grades are not written to the user's FSRS state.\n- **Respect the scope.** Only discuss content the tools return (the user's own\n submissions and followed collections).\n\nFor a durable artefact (a worksheet or quiz file) instead of a conversation, use\nthe `lingochunk-lesson` skill.",
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
//# sourceMappingURL=guides.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"guides.js","sourceRoot":"","sources":["../../src/generated/guides.ts"],"names":[],"mappings":"AAAA,uEAAuE;AACvE,qEAAqE;AACrE,wEAAwE;AACxE,mDAAmD;AAenD,MAAM,CAAC,MAAM,YAAY,GAA0B,CAAC,UAAU,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,SAAS,CAAU,CAAC;AAEhJ,MAAM,CAAC,MAAM,MAAM,GAA8B;IAC/C,UAAU,EAAE;QACV,KAAK,EAAE,UAAU;QACjB,UAAU,EAAE,qBAAqB;QACjC,WAAW,EAAE,oSAAoS;QACjT,IAAI,EAAE,gvIAAgvI;KACvvI;IACD,QAAQ,EAAE;QACR,KAAK,EAAE,QAAQ;QACf,UAAU,EAAE,mBAAmB;QAC/B,WAAW,EAAE,ovBAAovB;QACjwB,IAAI,EAAE,q4pBAAq4pB;KAC54pB;IACD,QAAQ,EAAE;QACR,KAAK,EAAE,QAAQ;QACf,UAAU,EAAE,mBAAmB;QAC/B,WAAW,EAAE,8YAA8Y;QAC3Z,IAAI,EAAE,41KAA41K;KACn2K;IACD,OAAO,EAAE;QACP,KAAK,EAAE,OAAO;QACd,UAAU,EAAE,kBAAkB;QAC9B,WAAW,EAAE,kfAAkf;QAC/f,IAAI,EAAE,srJAAsrJ;KAC7rJ;IACD,aAAa,EAAE;QACb,KAAK,EAAE,aAAa;QACpB,UAAU,EAAE,qBAAqB;QACjC,WAAW,EAAE,8dAA8d;QAC3e,IAAI,EAAE,isQAAisQ;KACxsQ;IACD,cAAc,EAAE;QACd,KAAK,EAAE,cAAc;QACrB,UAAU,EAAE,yBAAyB;QACrC,WAAW,EAAE,0jBAA0jB;QACvkB,IAAI,EAAE,inWAAinW;KACxnW;IACD,SAAS,EAAE;QACT,KAAK,EAAE,SAAS;QAChB,UAAU,EAAE,oBAAoB;QAChC,WAAW,EAAE,uaAAua;QACpb,IAAI,EAAE,moFAAmoF;KAC1oF;CACF,CAAC"}
|
package/dist/http.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { type Server } from "node:http";
|
|
2
|
+
import type { HttpConfig } from "./config.js";
|
|
3
|
+
/** Options for the hosted (Streamable HTTP) server. */
|
|
4
|
+
export interface HttpServerOptions extends HttpConfig {
|
|
5
|
+
/** Server version reported in the MCP handshake. */
|
|
6
|
+
version: string;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Serve the MCP server over Streamable HTTP for remote clients.
|
|
10
|
+
*
|
|
11
|
+
* Stateless by design: every POST builds a fresh McpServer + transport bound
|
|
12
|
+
* to the caller's own Bearer token, so one process serves many users with no
|
|
13
|
+
* session affinity and no token ever outliving its request. The token is not
|
|
14
|
+
* validated here - it is forwarded verbatim and the LingoChunk API stays the
|
|
15
|
+
* single authority (a bad token fails at the first tool call with the API's
|
|
16
|
+
* own 401 message).
|
|
17
|
+
*
|
|
18
|
+
* Endpoints: POST /mcp (the MCP wire), GET /health (liveness). GET/DELETE
|
|
19
|
+
* /mcp return 405: stateless mode has no server-push stream and no session
|
|
20
|
+
* to delete.
|
|
21
|
+
*/
|
|
22
|
+
export declare function startHttpServer(options: HttpServerOptions): Promise<Server>;
|
package/dist/http.js
ADDED
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import { createServer, } from "node:http";
|
|
2
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
3
|
+
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
|
|
4
|
+
import { LingoChunkClient } from "./client.js";
|
|
5
|
+
import { registerTools } from "./tools.js";
|
|
6
|
+
import { registerPrompts } from "./prompts.js";
|
|
7
|
+
// Remote MCP clients (claude.ai, ChatGPT, Le Chat, ...) call server-to-server,
|
|
8
|
+
// but browser-based clients (the MCP inspector, web IDEs) preflight with CORS.
|
|
9
|
+
// The wildcard origin is safe: authentication is a per-request Bearer token,
|
|
10
|
+
// never a cookie, so no ambient credentials can be replayed cross-origin.
|
|
11
|
+
const CORS_HEADERS = {
|
|
12
|
+
"Access-Control-Allow-Origin": "*",
|
|
13
|
+
"Access-Control-Allow-Methods": "GET, POST, DELETE, OPTIONS",
|
|
14
|
+
"Access-Control-Allow-Headers": "Content-Type, Authorization, Mcp-Session-Id, Mcp-Protocol-Version, Last-Event-ID",
|
|
15
|
+
"Access-Control-Expose-Headers": "Mcp-Session-Id, Mcp-Protocol-Version",
|
|
16
|
+
};
|
|
17
|
+
function applyCors(res) {
|
|
18
|
+
for (const [name, value] of Object.entries(CORS_HEADERS)) {
|
|
19
|
+
res.setHeader(name, value);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
function sendJson(res, status, body, headers = {}) {
|
|
23
|
+
res.writeHead(status, { "Content-Type": "application/json", ...headers });
|
|
24
|
+
res.end(JSON.stringify(body));
|
|
25
|
+
}
|
|
26
|
+
/** Extract the Bearer credential, or null when absent/malformed. */
|
|
27
|
+
function bearerToken(req) {
|
|
28
|
+
const header = req.headers.authorization;
|
|
29
|
+
if (!header)
|
|
30
|
+
return null;
|
|
31
|
+
const match = /^Bearer\s+(.+)$/i.exec(header);
|
|
32
|
+
const token = match?.[1]?.trim();
|
|
33
|
+
return token ? token : null;
|
|
34
|
+
}
|
|
35
|
+
function unauthorized(res, publicOrigin) {
|
|
36
|
+
// JSON-RPC error shape so MCP clients surface the message; -32001 is the
|
|
37
|
+
// de-facto "auth required" code used across MCP servers. resource_metadata
|
|
38
|
+
// (RFC 9728) is what OAuth-capable clients (claude.ai, ChatGPT, Gemini)
|
|
39
|
+
// follow to discover the sign-in flow served by the main app.
|
|
40
|
+
sendJson(res, 401, {
|
|
41
|
+
jsonrpc: "2.0",
|
|
42
|
+
error: {
|
|
43
|
+
code: -32001,
|
|
44
|
+
message: "Authentication required. Sign in via OAuth (your client offers " +
|
|
45
|
+
"this automatically), or create a personal access token in your " +
|
|
46
|
+
"LingoChunk account settings (Settings -> API tokens, it starts " +
|
|
47
|
+
"with 'lcp_') and send it as 'Authorization: Bearer <token>'. " +
|
|
48
|
+
"For clients without a token field, put it in the URL instead: " +
|
|
49
|
+
"/mcp/t/<token>.",
|
|
50
|
+
},
|
|
51
|
+
id: null,
|
|
52
|
+
}, {
|
|
53
|
+
"WWW-Authenticate": 'Bearer realm="LingoChunk", error="invalid_token", ' +
|
|
54
|
+
`resource_metadata="${publicOrigin}/.well-known/oauth-protected-resource/mcp"`,
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Serve the MCP server over Streamable HTTP for remote clients.
|
|
59
|
+
*
|
|
60
|
+
* Stateless by design: every POST builds a fresh McpServer + transport bound
|
|
61
|
+
* to the caller's own Bearer token, so one process serves many users with no
|
|
62
|
+
* session affinity and no token ever outliving its request. The token is not
|
|
63
|
+
* validated here - it is forwarded verbatim and the LingoChunk API stays the
|
|
64
|
+
* single authority (a bad token fails at the first tool call with the API's
|
|
65
|
+
* own 401 message).
|
|
66
|
+
*
|
|
67
|
+
* Endpoints: POST /mcp (the MCP wire), GET /health (liveness). GET/DELETE
|
|
68
|
+
* /mcp return 405: stateless mode has no server-push stream and no session
|
|
69
|
+
* to delete.
|
|
70
|
+
*/
|
|
71
|
+
export function startHttpServer(options) {
|
|
72
|
+
const httpServer = createServer((req, res) => {
|
|
73
|
+
void handle(req, res, options).catch((err) => {
|
|
74
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
75
|
+
process.stderr.write(`lingochunk-mcp http error: ${message}\n`);
|
|
76
|
+
if (!res.headersSent) {
|
|
77
|
+
sendJson(res, 500, {
|
|
78
|
+
jsonrpc: "2.0",
|
|
79
|
+
error: { code: -32603, message: "Internal server error." },
|
|
80
|
+
id: null,
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
res.end();
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
return new Promise((resolve, reject) => {
|
|
89
|
+
httpServer.once("error", reject);
|
|
90
|
+
httpServer.listen(options.port, () => {
|
|
91
|
+
httpServer.removeListener("error", reject);
|
|
92
|
+
resolve(httpServer);
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
async function handle(req, res, options) {
|
|
97
|
+
applyCors(res);
|
|
98
|
+
// Serve the MCP wire on both /mcp and / : deployed behind a path-stripping
|
|
99
|
+
// proxy (kamal-proxy --path-prefix /mcp strips by default), requests to
|
|
100
|
+
// https://host/mcp arrive here as "/"; run directly (docker -p), they
|
|
101
|
+
// arrive as "/mcp". Health likewise answers /health and /mcp/health.
|
|
102
|
+
const rawPath = new URL(req.url ?? "/", "http://localhost").pathname;
|
|
103
|
+
let path = rawPath === "/mcp" || rawPath === "/"
|
|
104
|
+
? "/"
|
|
105
|
+
: rawPath.startsWith("/mcp/")
|
|
106
|
+
? rawPath.slice("/mcp".length)
|
|
107
|
+
: rawPath;
|
|
108
|
+
// Tokened-URL auth: /t/<token> is the MCP wire with the credential in the
|
|
109
|
+
// path, for clients whose connector UI has no header/token field and no
|
|
110
|
+
// OAuth-less fallback (claude.ai custom connectors). The URL is then a
|
|
111
|
+
// secret - it lands in proxy/access logs - which is acceptable as a
|
|
112
|
+
// documented stopgap because PATs are scoped and one-click revocable.
|
|
113
|
+
// An Authorization header, when present, still wins below.
|
|
114
|
+
let pathToken = null;
|
|
115
|
+
const tokened = /^\/t\/([^/]+)$/.exec(path);
|
|
116
|
+
if (tokened?.[1]) {
|
|
117
|
+
pathToken = decodeURIComponent(tokened[1]).trim() || null;
|
|
118
|
+
path = "/";
|
|
119
|
+
}
|
|
120
|
+
if (req.method === "OPTIONS") {
|
|
121
|
+
res.writeHead(204).end();
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
if (path === "/health" && req.method === "GET") {
|
|
125
|
+
sendJson(res, 200, {
|
|
126
|
+
status: "ok",
|
|
127
|
+
name: "lingochunk-mcp",
|
|
128
|
+
version: options.version,
|
|
129
|
+
transport: "streamable-http",
|
|
130
|
+
});
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
if (path !== "/") {
|
|
134
|
+
sendJson(res, 404, { detail: "Not found. The MCP endpoint is POST /mcp." });
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
if (req.method !== "POST") {
|
|
138
|
+
sendJson(res, 405, {
|
|
139
|
+
jsonrpc: "2.0",
|
|
140
|
+
error: {
|
|
141
|
+
code: -32000,
|
|
142
|
+
message: "Method not allowed. This server is stateless: POST /mcp only.",
|
|
143
|
+
},
|
|
144
|
+
id: null,
|
|
145
|
+
}, { Allow: "POST" });
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
const token = bearerToken(req) ?? pathToken;
|
|
149
|
+
if (!token) {
|
|
150
|
+
unauthorized(res, options.publicOrigin);
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
// Fresh server per request: tools close over THIS caller's client. clipDir
|
|
154
|
+
// is never used because remote mode does not register get_audio_clip.
|
|
155
|
+
const client = new LingoChunkClient({
|
|
156
|
+
baseUrl: options.baseUrl,
|
|
157
|
+
token,
|
|
158
|
+
clipDir: "",
|
|
159
|
+
});
|
|
160
|
+
const server = new McpServer({ name: "lingochunk", version: options.version });
|
|
161
|
+
registerTools(server, client, { baseUrl: options.baseUrl, token, clipDir: "" }, "remote");
|
|
162
|
+
registerPrompts(server);
|
|
163
|
+
const transport = new StreamableHTTPServerTransport({
|
|
164
|
+
sessionIdGenerator: undefined,
|
|
165
|
+
enableJsonResponse: true,
|
|
166
|
+
});
|
|
167
|
+
res.on("close", () => {
|
|
168
|
+
void transport.close();
|
|
169
|
+
void server.close();
|
|
170
|
+
});
|
|
171
|
+
await server.connect(transport);
|
|
172
|
+
await transport.handleRequest(req, res);
|
|
173
|
+
}
|
|
174
|
+
//# sourceMappingURL=http.js.map
|
package/dist/http.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http.js","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -2,9 +2,11 @@
|
|
|
2
2
|
import { readFileSync } from "node:fs";
|
|
3
3
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
4
4
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
5
|
-
import { loadConfig } from "./config.js";
|
|
5
|
+
import { loadConfig, loadHttpConfig } from "./config.js";
|
|
6
6
|
import { LingoChunkClient } from "./client.js";
|
|
7
|
+
import { startHttpServer } from "./http.js";
|
|
7
8
|
import { registerTools } from "./tools.js";
|
|
9
|
+
import { registerPrompts } from "./prompts.js";
|
|
8
10
|
// Single source of truth for the version: the package manifest. A hardcoded
|
|
9
11
|
// copy here once drifted (the server reported 0.2.1 while npm shipped 0.3.0),
|
|
10
12
|
// which made "is my server up to date?" unanswerable.
|
|
@@ -17,12 +19,22 @@ if (process.argv.includes("--version") || process.argv.includes("-v")) {
|
|
|
17
19
|
process.exit(0);
|
|
18
20
|
}
|
|
19
21
|
async function main() {
|
|
22
|
+
// --http runs the hosted multi-user server (Streamable HTTP, per-request
|
|
23
|
+
// Bearer tokens) instead of the single-user stdio process.
|
|
24
|
+
if (process.argv.includes("--http")) {
|
|
25
|
+
const httpConfig = loadHttpConfig();
|
|
26
|
+
await startHttpServer({ ...httpConfig, version: VERSION });
|
|
27
|
+
process.stderr.write(`lingochunk-mcp ${VERSION} listening on :${httpConfig.port} ` +
|
|
28
|
+
`(POST /mcp), API ${httpConfig.baseUrl}\n`);
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
20
31
|
// Fail fast (to stderr, never stdout - stdout is the MCP wire) if the token
|
|
21
32
|
// is missing, so onboarding surfaces the problem immediately.
|
|
22
33
|
const config = loadConfig();
|
|
23
34
|
const client = new LingoChunkClient(config);
|
|
24
35
|
const server = new McpServer({ name: "lingochunk", version: VERSION });
|
|
25
36
|
registerTools(server, client, config);
|
|
37
|
+
registerPrompts(server);
|
|
26
38
|
const transport = new StdioServerTransport();
|
|
27
39
|
await server.connect(transport);
|
|
28
40
|
}
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AACzD,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAE/C,4EAA4E;AAC5E,8EAA8E;AAC9E,sDAAsD;AACtD,MAAM,OAAO,GACX,IAAI,CAAC,KAAK,CACR,YAAY,CAAC,IAAI,GAAG,CAAC,iBAAiB,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,CAEpE,CAAC,OAAO,CAAC;AAEV,2EAA2E;AAC3E,0EAA0E;AAC1E,2EAA2E;AAC3E,IAAI,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;IACtE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,OAAO,IAAI,CAAC,CAAC;IACrC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAED,KAAK,UAAU,IAAI;IACjB,yEAAyE;IACzE,2DAA2D;IAC3D,IAAI,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;QACpC,MAAM,UAAU,GAAG,cAAc,EAAE,CAAC;QACpC,MAAM,eAAe,CAAC,EAAE,GAAG,UAAU,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;QAC3D,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,kBAAkB,OAAO,kBAAkB,UAAU,CAAC,IAAI,GAAG;YAC3D,oBAAoB,UAAU,CAAC,OAAO,IAAI,CAC7C,CAAC;QACF,OAAO;IACT,CAAC;IAED,4EAA4E;IAC5E,8DAA8D;IAC9D,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAC5B,MAAM,MAAM,GAAG,IAAI,gBAAgB,CAAC,MAAM,CAAC,CAAC;IAE5C,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;IACvE,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,eAAe,CAAC,MAAM,CAAC,CAAC;IAExB,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;AAClC,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAY,EAAE,EAAE;IAC5B,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IACjE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,mCAAmC,OAAO,IAAI,CAAC,CAAC;IACrE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
|