@clien-ai/mcp 0.1.3 → 0.1.4

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 CHANGED
@@ -68,6 +68,25 @@ the top 3 threats", etc.
68
68
 
69
69
  ---
70
70
 
71
+ ## Recipes: composing beyond the hero
72
+
73
+ `clien_research` is the hero — the recommended default for validating an idea
74
+ end to end. Alongside it, the server exposes granular primitives (`create_persona`,
75
+ `interview_persona`, `list_projects` / `create_project`, `list_reports` /
76
+ `get_report`, `clien_research_status`) you can sequence for targeted, cheaper
77
+ checks.
78
+
79
+ See [`docs/recipes/`](../docs/recipes/) for the supported compositions:
80
+
81
+ - [Competitor spot-check](../docs/recipes/competitor-spot-check.md) — read `competitors[]` from a report instead of commissioning a new study
82
+ - [Pivot viability](../docs/recipes/pivot-viability.md) — research a pivot and compare it against the original
83
+ - [New-market persona validation](../docs/recipes/new-market-persona-validation.md) — `create_persona` → `interview_persona`, no credits, no full run
84
+
85
+ Rule of thumb: for a **full** validation, call the hero; reach for a primitive
86
+ composition only for a **narrow, cheaper probe**.
87
+
88
+ ---
89
+
71
90
  ## Inputs
72
91
 
73
92
  | Field | Type | Required | Default | Notes |
package/dist/server.js CHANGED
@@ -1,8 +1,10 @@
1
1
  /**
2
2
  * MCP stdio server entry point.
3
3
  *
4
- * Registers the `clien_research` tool. Auth happens lazily on first tool call
5
- * so the server can announce its tool list without a browser interruption.
4
+ * The tool surface lives in `tools/registry.ts` — both `tools/list` and
5
+ * `tools/call` iterate the `TOOLS` array, so adding a tool needs no edits here.
6
+ * Auth happens lazily on first tool call so the server can announce its tool
7
+ * list without a browser interruption.
6
8
  */
7
9
  import { Server } from '@modelcontextprotocol/sdk/server/index.js';
8
10
  import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
@@ -10,8 +12,8 @@ import { CallToolRequestSchema, ListToolsRequestSchema, } from '@modelcontextpro
10
12
  import { loadConfig, PACKAGE_NAME, PACKAGE_VERSION } from './config.js';
11
13
  import { ensureSession, } from './auth/oauth.js';
12
14
  import { clearTokens, loadRefreshToken, saveRefreshToken, withTokenLock, } from './auth/storage.js';
13
- import { ResearchToolError, runResearch, } from './tools/research.js';
14
- import { StatusToolError, getResearchStatus, } from './tools/status.js';
15
+ import { ToolError } from './tools/errors.js';
16
+ import { TOOLS } from './tools/registry.js';
15
17
  function log(...args) {
16
18
  // stderr only — stdout is the MCP transport.
17
19
  console.error('[clien-mcp]', ...args);
@@ -29,88 +31,6 @@ async function defaultBrowserOpener() {
29
31
  await fn(url);
30
32
  };
31
33
  }
32
- /**
33
- * Input schema for the tool advert. Hand-rolled JSON Schema so we avoid the
34
- * `zod-to-json-schema` dependency. Must stay in sync with `ResearchInputSchema`
35
- * in `src/tools/research.ts` — the Zod parser is still the source of truth at
36
- * runtime; this is only the spec advertised to the caller.
37
- *
38
- * Drift surfaces silently: the Zod parser still accepts the input, but strict
39
- * MCP clients (`additionalProperties: false`) strip undeclared fields before
40
- * they reach the parser, and LLM callers never learn the field exists.
41
- * Enforcement: `__tests__/schema-contract.test.ts` walks both schemas and
42
- * fails if their property keys or required-field sets diverge. Exported here
43
- * so that test can import it. See
44
- * `docs/solutions/design-patterns/cross-package-schema-duplication-contract-2026-05-12.md`.
45
- */
46
- export const RESEARCH_INPUT_SCHEMA = {
47
- type: 'object',
48
- properties: {
49
- idea: {
50
- type: 'string',
51
- minLength: 1,
52
- maxLength: 10_000,
53
- description: 'The product idea, feature hypothesis, or research question to validate. ' +
54
- 'Can be a one-liner or several paragraphs — more context yields a better report.',
55
- },
56
- depth: {
57
- type: 'string',
58
- enum: ['quick', 'deep'],
59
- default: 'deep',
60
- description: '"deep" (default) runs a 15-25 minute full research pass. ' +
61
- '"quick" caps cost and runs a tighter pass.',
62
- },
63
- project_id: {
64
- type: 'string',
65
- format: 'uuid',
66
- description: 'Optional Clien.ai project UUID to attach this run to. When omitted, ' +
67
- 'the run is standalone and not associated with any project.',
68
- },
69
- project_name: {
70
- type: 'string',
71
- minLength: 1,
72
- maxLength: 100,
73
- description: 'Name for a new Clien.ai project to attach this run to. You SHOULD ' +
74
- 'supply this whenever `project_id` is not set, otherwise the ' +
75
- 'resulting report will not be discoverable in the Clien.ai web UI. ' +
76
- 'Derive a short (2-4 word) human-readable name from the idea — ' +
77
- 'typically the product name. Guidance on when to create a new ' +
78
- 'project vs. reuse an existing one: create a NEW project (supply a ' +
79
- 'fresh `project_name`) for each distinct research idea or product ' +
80
- 'concept; REUSE an existing `project_id` only when the user ' +
81
- 'explicitly asks to add follow-up research to a prior run on the ' +
82
- 'same idea. Ignored when `project_id` is also provided.',
83
- },
84
- },
85
- required: ['idea'],
86
- additionalProperties: false,
87
- };
88
- /**
89
- * Hand-rolled JSON Schema advert for `clien_research_status`. Same
90
- * Zod-vs-JSON-schema duplication rules as RESEARCH_INPUT_SCHEMA above:
91
- * the runtime parser in tools/status.ts:StatusInputSchema is the source
92
- * of truth; this is the advert. Drift is caught by the schema-contract
93
- * test in __tests__/schema-contract.test.ts.
94
- */
95
- export const RESEARCH_STATUS_INPUT_SCHEMA = {
96
- type: 'object',
97
- properties: {
98
- job_id: {
99
- type: 'string',
100
- format: 'uuid',
101
- description: 'UUID of the research job to query. Returned in the `_meta.job_id` ' +
102
- 'field of a prior `clien_research` call, surfaced in error ' +
103
- 'messages when a run dropped mid-flight (e.g. "MCP error -32000"), ' +
104
- 'and printed to the MCP server\'s stderr log as ' +
105
- '`[clien-mcp] research started job_id=<uuid>` at run start. Use ' +
106
- 'this tool to RECOVER an in-flight job instead of calling ' +
107
- '`clien_research` again — calling research again would spawn a ' +
108
- 'new run and debit another 5 credits for the same outcome.',
109
- },
110
- },
111
- required: ['job_id'],
112
- additionalProperties: false,
113
- };
114
34
  export function createMcpServer() {
115
35
  const config = loadConfig();
116
36
  // Per-instance session cache. Scoping this to the closure (rather than the
@@ -142,31 +62,11 @@ export function createMcpServer() {
142
62
  }
143
63
  const server = new Server({ name: PACKAGE_NAME, version: PACKAGE_VERSION }, { capabilities: { tools: {} } });
144
64
  server.setRequestHandler(ListToolsRequestSchema, async () => ({
145
- tools: [
146
- {
147
- name: 'clien_research',
148
- description: 'Run a full product-research pass on an idea. Returns a markdown report plus ' +
149
- 'structured report_data (hypotheses, competitors[], key findings). Typical wall time ' +
150
- '15-25 minutes; progress is streamed via notifications/progress. ' +
151
- 'First call opens a browser for one-time OAuth login; subsequent calls reuse the stored refresh token. ' +
152
- 'IMPORTANT: if this call fails mid-flight with "MCP error -32000: Connection closed", ' +
153
- 'do NOT call clien_research again — that spawns a new run and debits another 5 credits for the same idea. ' +
154
- 'Instead call `clien_research_status` with the job_id from the prior call\'s `_meta.job_id` ' +
155
- '(or from the `[clien-mcp] research started job_id=…` line in the MCP server\'s stderr log).',
156
- inputSchema: RESEARCH_INPUT_SCHEMA,
157
- },
158
- {
159
- name: 'clien_research_status',
160
- description: 'Fetch the current state of an existing `clien_research` job. Use this to ' +
161
- 'recover a run that disconnected with -32000 mid-flight (the job keeps running ' +
162
- 'on the backend; this tool re-attaches a read view) and to poll for completion. ' +
163
- 'If the job is complete, returns the full markdown report and structured report_data ' +
164
- 'in the same shape `clien_research` would have returned — no need to call research again. ' +
165
- 'If the job is still running, returns a brief status summary. If the job failed or ' +
166
- 'was cancelled, returns the failure reason. Read-only: no credit cost, no side effects.',
167
- inputSchema: RESEARCH_STATUS_INPUT_SCHEMA,
168
- },
169
- ],
65
+ tools: TOOLS.map((tool) => ({
66
+ name: tool.name,
67
+ description: tool.description,
68
+ inputSchema: tool.jsonSchema,
69
+ })),
170
70
  }));
171
71
  server.setRequestHandler(CallToolRequestSchema, async (request) => {
172
72
  const toolName = request.params.name;
@@ -176,7 +76,8 @@ export function createMcpServer() {
176
76
  // inside the try-catch would convert it to a tool-level `isError`
177
77
  // response — the wrong shape, and a regression caught by
178
78
  // server.test.ts > 'unknown tool name surfaces an error'.
179
- if (toolName !== 'clien_research' && toolName !== 'clien_research_status') {
79
+ const tool = TOOLS.find((t) => t.name === toolName);
80
+ if (!tool) {
180
81
  throw new Error(`Unknown tool: ${toolName}`);
181
82
  }
182
83
  // Per MCP spec, `progressToken` may be a string OR a number, and `0` or
@@ -203,46 +104,28 @@ export function createMcpServer() {
203
104
  : undefined;
204
105
  try {
205
106
  const session = await getSession();
206
- if (toolName === 'clien_research') {
207
- const result = await runResearch(request.params.arguments, {
208
- config,
209
- session,
210
- onProgress,
211
- invalidateSession,
212
- });
213
- return {
214
- content: result.content,
215
- _meta: result._meta,
216
- };
217
- }
218
- if (toolName === 'clien_research_status') {
219
- const result = await getResearchStatus(request.params.arguments, {
220
- config,
221
- session,
222
- invalidateSession,
223
- });
224
- return {
225
- content: result.content,
226
- _meta: result._meta,
227
- };
228
- }
229
- // Unreachable: the pre-try unknown-tool guard above narrows toolName
230
- // to the two valid names. Kept as a defense-in-depth fallback.
231
- throw new Error(`Unknown tool: ${toolName}`);
107
+ const result = await tool.handler(request.params.arguments, {
108
+ config,
109
+ session,
110
+ onProgress,
111
+ invalidateSession,
112
+ });
113
+ return {
114
+ content: result.content,
115
+ _meta: result._meta,
116
+ };
232
117
  }
233
118
  catch (err) {
234
- const message = err instanceof ResearchToolError || err instanceof StatusToolError
119
+ const message = err instanceof ToolError
235
120
  ? err.userMessage
236
121
  : err instanceof Error
237
122
  ? err.message
238
123
  : String(err);
239
124
  // Preserve the job_id on error responses so the host AI can pivot to
240
125
  // `clien_research_status` (or surface the id to the user) without
241
- // having to parse it out of the human-readable error text. Both error
126
+ // having to parse it out of the human-readable error text. Tool error
242
127
  // classes carry a `jobId` field when one is known.
243
- const errorJobId = err instanceof ResearchToolError || err instanceof StatusToolError
244
- ? err.jobId
245
- : undefined;
128
+ const errorJobId = err instanceof ToolError ? err.jobId : undefined;
246
129
  log('tool error:', message);
247
130
  return {
248
131
  isError: true,
@@ -1 +1 @@
1
- {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Shared base class for tool-level errors.
3
+ *
4
+ * Every registry tool signals a user-recoverable failure by throwing a
5
+ * subclass of `ToolError`. The server's `CallTool` catch block maps any
6
+ * `ToolError` to a tool-level `{ isError: true, content, _meta.job_id? }`
7
+ * response (as opposed to a JSON-RPC protocol error). Carrying `userMessage`
8
+ * and the optional `jobId` on a single base means the dispatch needs exactly
9
+ * one `instanceof ToolError` check regardless of how many tools the registry
10
+ * holds — see `src/server.ts`.
11
+ */
12
+ export class ToolError extends Error {
13
+ userMessage;
14
+ jobId;
15
+ constructor(userMessage, opts = {}) {
16
+ super(userMessage);
17
+ this.userMessage = userMessage;
18
+ this.jobId = opts.jobId;
19
+ if (opts.cause !== undefined)
20
+ this.cause = opts.cause;
21
+ }
22
+ }
23
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/tools/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,MAAM,OAAO,SAAU,SAAQ,KAAK;IACzB,WAAW,CAAQ;IACnB,KAAK,CAAS;IACvB,YAAY,WAAmB,EAAE,OAA4C,EAAE;QAC7E,KAAK,CAAC,WAAW,CAAC,CAAA;QAClB,IAAI,CAAC,WAAW,GAAG,WAAW,CAAA;QAC9B,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAA;QACvB,IAAI,IAAI,CAAC,KAAK,KAAK,SAAS;YAAG,IAA4B,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAA;IAChF,CAAC;CACF"}
@@ -0,0 +1,263 @@
1
+ /**
2
+ * `interview_persona` — stateful, full-lifecycle interview tool over the
3
+ * interview REST API (FUL-17 lifecycle + FUL-43 conversational turn). Lets an
4
+ * agent drive a real multi-turn interview with a persona: start it, exchange
5
+ * turns (each returns the persona's FULL reply), read the transcript, and
6
+ * complete/reopen — reusing the same lifecycle as the web app (greeting seed,
7
+ * auto-summary on message thresholds, message-count maintenance), so an
8
+ * MCP-driven interview is indistinguishable from a web one in the DB.
9
+ *
10
+ * Like `personas.ts` / `projects.ts` this is a thin bearer-auth HTTP client: it
11
+ * reuses the shared `apiCall` from `research.ts` (401→refresh→retry, per-endpoint
12
+ * timeouts). No new HTTP machinery.
13
+ *
14
+ * One tool, many actions (an `action` discriminator on a FLAT object schema —
15
+ * the registry type and the schema-contract test both assume a `z.ZodObject`, so
16
+ * a `discriminatedUnion` is off the table). Per-action required fields are
17
+ * enforced in the handler, not via `.superRefine` (which would yield a
18
+ * `ZodEffects`, not a `ZodObject`).
19
+ *
20
+ * Contract (all bearer-authenticated, ownership derived from the parent project):
21
+ * - start → POST /api/interviews { projectId, personaId, withFirstMessage:true, ephemeral } → { interview, personaName, firstMessageContent }
22
+ * - turn → POST /api/interviews/{id}/turn { content } → { reply, message, userMessage, messageCount }
23
+ * - transcript → GET /api/interviews/{id} → { interview }
24
+ * - complete → PATCH /api/interviews/{id} { status:'completed' } → { interview }
25
+ * - reopen → PATCH /api/interviews/{id} { status:'active' } → { interview }
26
+ *
27
+ * The backend stamps `source='mcp'` automatically for bearer callers (FUL-21);
28
+ * `ephemeral: true` on `start` sets `include_in_insights=false`.
29
+ *
30
+ * Scope note: a `turn` generates a real AI reply, metered today only by the
31
+ * monthly usage limit. Per-turn credit debiting is deferred to FUL-33 (the turn
32
+ * endpoint and the generalized per-tool spend RPC / cost table aren't built yet).
33
+ */
34
+ import { z } from 'zod';
35
+ import { ToolError } from './errors.js';
36
+ import { apiCall, categorizeFetchError, truncate, } from './research.js';
37
+ const INTERVIEW_FETCH_TIMEOUT_MS = 60_000;
38
+ /** Upper bound on a turn's question — matches the server's `MESSAGE_CONTENT_MAX`. */
39
+ const CONTENT_MAX = 10_000;
40
+ export const InterviewPersonaInputSchema = z.object({
41
+ action: z
42
+ .enum(['start', 'turn', 'transcript', 'complete', 'reopen'])
43
+ .describe('What to do this call. Drive a full interview as a loop: `start` once to open an ' +
44
+ 'interview (seeds the persona\'s greeting), then `turn` repeatedly — send a question, ' +
45
+ 'read the persona\'s full reply, decide the next question. `transcript` re-reads the ' +
46
+ 'whole conversation. `complete` closes the interview when you\'ve learned enough ' +
47
+ '(5-12 turns is typical); `reopen` resumes a completed one.'),
48
+ projectId: z
49
+ .string()
50
+ .uuid()
51
+ .optional()
52
+ .describe('action=start: UUID of the project the interview belongs to. Get it from `list_projects` ' +
53
+ 'or `create_project`. You are 404\'d if you do not own it.'),
54
+ personaId: z
55
+ .string()
56
+ .uuid()
57
+ .optional()
58
+ .describe('action=start: UUID of the persona to interview (must belong to `projectId`). Get it from ' +
59
+ '`create_persona` (`_meta.persona.id`).'),
60
+ interviewId: z
61
+ .string()
62
+ .uuid()
63
+ .optional()
64
+ .describe('action=turn/transcript/complete/reopen: UUID of the interview to act on. Returned by ' +
65
+ '`start` in `_meta.interview.id`.'),
66
+ content: z
67
+ .string()
68
+ .trim()
69
+ .min(1, 'content must be non-empty')
70
+ .max(CONTENT_MAX, `content too long (max ${CONTENT_MAX} chars)`)
71
+ .optional()
72
+ .describe('action=turn: the next question to ask the persona. The persona\'s full reply comes back ' +
73
+ 'in the tool result text (and `_meta.reply`).'),
74
+ ephemeral: z
75
+ .boolean()
76
+ .optional()
77
+ .default(false)
78
+ .describe('action=start: set true for a scratch/throwaway interview that should NOT count toward the ' +
79
+ 'project\'s aggregate insights (sets include_in_insights=false). Leave false (the default) ' +
80
+ 'for a real interview you want reflected in project-level analysis.'),
81
+ });
82
+ export class InterviewToolError extends ToolError {
83
+ }
84
+ function formatZodError(error) {
85
+ return error.issues.map((i) => `${i.path.join('.') || 'input'}: ${i.message}`).join('; ');
86
+ }
87
+ function makeCtx(deps) {
88
+ return { config: deps.config, session: deps.session, fetch: deps.fetch ?? fetch };
89
+ }
90
+ /**
91
+ * Shared non-ok handling, mirroring `personas.ts`: 401 drops the cached session
92
+ * (so the next tool call rebuilds from disk) and surfaces a re-auth message;
93
+ * 404 means the interview/project isn't owned by the caller; 400 surfaces the
94
+ * server's validation detail; everything else surfaces a generic HTTP error.
95
+ */
96
+ async function throwForResponse(response, deps, action) {
97
+ const category = categorizeFetchError(response.status);
98
+ if (category === 'auth') {
99
+ if (response.refreshError?.kind !== 'transient')
100
+ deps.invalidateSession?.();
101
+ throw new InterviewToolError('Session expired. Re-run any Clien.ai tool to re-authenticate, then try again.');
102
+ }
103
+ if (response.status === 404) {
104
+ throw new InterviewToolError(`Could not ${action} — interview or project not found, or you don't own it. ` +
105
+ 'Confirm the ids (list_projects / the id from `start`).');
106
+ }
107
+ const text = await response.text().catch(() => '');
108
+ let detail = truncate(text, 200);
109
+ try {
110
+ const parsed = JSON.parse(text);
111
+ if (parsed?.error)
112
+ detail = `${parsed.error}${parsed.code ? ` (${parsed.code})` : ''}`;
113
+ }
114
+ catch {
115
+ // non-JSON body — fall back to the truncated raw text
116
+ }
117
+ if (response.status === 400) {
118
+ throw new InterviewToolError(`Could not ${action} — ${detail}`);
119
+ }
120
+ throw new InterviewToolError(`Failed to ${action} (HTTP ${response.status}): ${detail}`);
121
+ }
122
+ /** Run one `apiCall`, converting timeout/abort into a clear tool error. */
123
+ async function call(ctx, method, path, action, body) {
124
+ try {
125
+ return await apiCall(ctx, method, path, {
126
+ ...(body ? { body } : {}),
127
+ timeoutMs: INTERVIEW_FETCH_TIMEOUT_MS,
128
+ });
129
+ }
130
+ catch (err) {
131
+ const e = err;
132
+ if (e.name === 'AbortError' || e.name === 'TimeoutError') {
133
+ throw new InterviewToolError(`Request to ${action} timed out after ${INTERVIEW_FETCH_TIMEOUT_MS / 1000}s. ` +
134
+ 'It may or may not have been applied — fetch the transcript before retrying.');
135
+ }
136
+ throw err;
137
+ }
138
+ }
139
+ async function readJson(response) {
140
+ return (await response.json().catch(() => null));
141
+ }
142
+ function formatTranscript(interview) {
143
+ const messages = interview.messages ?? [];
144
+ const lines = messages.map((m) => {
145
+ const speaker = m.role === 'assistant' ? 'Persona' : 'Interviewer';
146
+ return `${speaker}: ${m.content ?? ''}`;
147
+ });
148
+ const header = `Interview ${interview.id ?? '?'} — status: ${interview.status ?? 'unknown'}, ` +
149
+ `${messages.length} message${messages.length === 1 ? '' : 's'}.`;
150
+ return lines.length > 0 ? `${header}\n\n${lines.join('\n\n')}` : header;
151
+ }
152
+ async function startInterview(input, ctx, deps) {
153
+ if (!input.projectId || !input.personaId) {
154
+ throw new InterviewToolError("action 'start' requires projectId and personaId.");
155
+ }
156
+ const response = await call(ctx, 'POST', '/api/interviews', 'start interview', {
157
+ projectId: input.projectId,
158
+ personaId: input.personaId,
159
+ withFirstMessage: true,
160
+ ephemeral: input.ephemeral,
161
+ });
162
+ if (!response.ok)
163
+ await throwForResponse(response, deps, 'start interview');
164
+ const json = await readJson(response);
165
+ const interview = json?.interview;
166
+ if (!interview?.id) {
167
+ throw new InterviewToolError('Interview creation returned no interview id; the operation may not have succeeded.');
168
+ }
169
+ const who = json?.personaName ? ` with ${json.personaName}` : '';
170
+ const greeting = json?.firstMessageContent ? `\nGreeting: ${json.firstMessageContent}` : '';
171
+ const insightsNote = input.ephemeral
172
+ ? ' Marked ephemeral — excluded from project insights.'
173
+ : '';
174
+ return {
175
+ content: [
176
+ {
177
+ type: 'text',
178
+ text: `Started interview ${interview.id}${who}.${insightsNote}${greeting}\n` +
179
+ "Ask questions with action='turn'; close it with action='complete' when done.",
180
+ },
181
+ ],
182
+ _meta: { interview, personaName: json?.personaName, firstMessageContent: json?.firstMessageContent },
183
+ };
184
+ }
185
+ async function sendTurn(input, ctx, deps) {
186
+ if (!input.interviewId || !input.content) {
187
+ throw new InterviewToolError("action 'turn' requires interviewId and content.");
188
+ }
189
+ const response = await call(ctx, 'POST', `/api/interviews/${input.interviewId}/turn`, 'send interview turn', { content: input.content });
190
+ if (!response.ok)
191
+ await throwForResponse(response, deps, 'send interview turn');
192
+ const json = await readJson(response);
193
+ const reply = json?.reply;
194
+ if (typeof reply !== 'string' || reply.length === 0) {
195
+ throw new InterviewToolError('Turn returned no persona reply; the turn may not have succeeded.');
196
+ }
197
+ return {
198
+ content: [{ type: 'text', text: reply }],
199
+ _meta: {
200
+ reply,
201
+ messageCount: json?.messageCount,
202
+ message: json?.message,
203
+ userMessage: json?.userMessage,
204
+ },
205
+ };
206
+ }
207
+ async function fetchTranscript(input, ctx, deps) {
208
+ if (!input.interviewId) {
209
+ throw new InterviewToolError("action 'transcript' requires interviewId.");
210
+ }
211
+ const response = await call(ctx, 'GET', `/api/interviews/${input.interviewId}`, 'fetch transcript');
212
+ if (!response.ok)
213
+ await throwForResponse(response, deps, 'fetch transcript');
214
+ const json = await readJson(response);
215
+ const interview = json?.interview;
216
+ if (!interview?.id) {
217
+ throw new InterviewToolError('Transcript fetch returned no interview.');
218
+ }
219
+ return {
220
+ content: [{ type: 'text', text: formatTranscript(interview) }],
221
+ _meta: { interview },
222
+ };
223
+ }
224
+ async function setStatus(input, ctx, deps, status) {
225
+ const action = status === 'completed' ? 'complete' : 'reopen';
226
+ if (!input.interviewId) {
227
+ throw new InterviewToolError(`action '${action}' requires interviewId.`);
228
+ }
229
+ const response = await call(ctx, 'PATCH', `/api/interviews/${input.interviewId}`, `${action} interview`, { status });
230
+ if (!response.ok)
231
+ await throwForResponse(response, deps, `${action} interview`);
232
+ const json = await readJson(response);
233
+ const interview = json?.interview;
234
+ if (!interview?.id) {
235
+ throw new InterviewToolError(`Could not ${action} interview — no interview returned.`);
236
+ }
237
+ const verb = status === 'completed' ? 'Completed' : 'Reopened';
238
+ return {
239
+ content: [{ type: 'text', text: `${verb} interview ${interview.id} (status: ${interview.status ?? status}).` }],
240
+ _meta: { interview },
241
+ };
242
+ }
243
+ export async function interviewPersona(input, deps) {
244
+ const parsed = InterviewPersonaInputSchema.safeParse(input);
245
+ if (!parsed.success) {
246
+ throw new InterviewToolError(`Invalid input — ${formatZodError(parsed.error)}`);
247
+ }
248
+ const ctx = makeCtx(deps);
249
+ const data = parsed.data;
250
+ switch (data.action) {
251
+ case 'start':
252
+ return startInterview(data, ctx, deps);
253
+ case 'turn':
254
+ return sendTurn(data, ctx, deps);
255
+ case 'transcript':
256
+ return fetchTranscript(data, ctx, deps);
257
+ case 'complete':
258
+ return setStatus(data, ctx, deps, 'completed');
259
+ case 'reopen':
260
+ return setStatus(data, ctx, deps, 'active');
261
+ }
262
+ }
263
+ //# sourceMappingURL=interview.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interview.js","sourceRoot":"","sources":["../../src/tools/interview.ts"],"names":[],"mappings":"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"}