@studiometa/productive-mcp 0.10.14 → 0.10.16
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/dist/handlers/api-read.d.ts +2 -1
- package/dist/handlers/api-read.d.ts.map +1 -1
- package/dist/handlers/api-utils.d.ts +20 -0
- package/dist/handlers/api-utils.d.ts.map +1 -1
- package/dist/handlers/help.d.ts +20 -0
- package/dist/handlers/help.d.ts.map +1 -1
- package/dist/handlers/index.d.ts.map +1 -1
- package/dist/handlers/run-endpoint.d.ts +27 -0
- package/dist/handlers/run-endpoint.d.ts.map +1 -0
- package/dist/handlers/run.d.ts +28 -0
- package/dist/handlers/run.d.ts.map +1 -0
- package/dist/handlers/search-docs.d.ts +22 -0
- package/dist/handlers/search-docs.d.ts.map +1 -0
- package/dist/{handlers-BE96O-uy.js → handlers-Ca2x4dM8.js} +1050 -11
- package/dist/handlers-Ca2x4dM8.js.map +1 -0
- package/dist/handlers.js +1 -1
- package/dist/{http-DF9K8Fr4.js → http-xNZOdN_t.js} +72 -4
- package/dist/http-xNZOdN_t.js.map +1 -0
- package/dist/http.d.ts.map +1 -1
- package/dist/http.js +1 -1
- package/dist/index.js +2 -2
- package/dist/oauth.js +1 -1
- package/dist/run/bridge.d.ts +53 -0
- package/dist/run/bridge.d.ts.map +1 -0
- package/dist/run/docs.d.ts +23 -0
- package/dist/run/docs.d.ts.map +1 -0
- package/dist/run/engine.d.ts +60 -0
- package/dist/run/engine.d.ts.map +1 -0
- package/dist/run/limits.d.ts +33 -0
- package/dist/run/limits.d.ts.map +1 -0
- package/dist/run/prelude.d.ts +27 -0
- package/dist/run/prelude.d.ts.map +1 -0
- package/dist/run/remote.d.ts +44 -0
- package/dist/run/remote.d.ts.map +1 -0
- package/dist/run/render.d.ts +30 -0
- package/dist/run/render.d.ts.map +1 -0
- package/dist/run/strip.d.ts +20 -0
- package/dist/run/strip.d.ts.map +1 -0
- package/dist/schema.d.ts +13 -2
- package/dist/schema.d.ts.map +1 -1
- package/dist/server.js +2 -2
- package/dist/{stdio-BnfO285Q.js → stdio-jqfOnE6-.js} +2 -2
- package/dist/{stdio-BnfO285Q.js.map → stdio-jqfOnE6-.js.map} +1 -1
- package/dist/stdio.js +1 -1
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +93 -4
- package/dist/tools.js.map +1 -1
- package/dist/{version-XQYsroYk.js → version-Jj_0Ypf8.js} +3 -3
- package/dist/{version-XQYsroYk.js.map → version-Jj_0Ypf8.js.map} +1 -1
- package/package.json +5 -3
- package/skills/SKILL.md +84 -1
- package/dist/handlers-BE96O-uy.js.map +0 -1
- package/dist/http-DF9K8Fr4.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { a as INSTRUCTIONS, i as readResource, n as listResourceTemplates, r as listResources, t as VERSION } from "./version-
|
|
3
|
-
import { a as handlePrompt, n as getAvailableTools, s as handleToolCall, t as getAvailablePrompts } from "./stdio-
|
|
2
|
+
import { a as INSTRUCTIONS, i as readResource, n as listResourceTemplates, r as listResources, t as VERSION } from "./version-Jj_0Ypf8.js";
|
|
3
|
+
import { a as handlePrompt, n as getAvailableTools, s as handleToolCall, t as getAvailablePrompts } from "./stdio-jqfOnE6-.js";
|
|
4
4
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
5
5
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
6
6
|
import { CallToolRequestSchema, GetPromptRequestSchema, ListPromptsRequestSchema, ListResourceTemplatesRequestSchema, ListResourcesRequestSchema, ListToolsRequestSchema, ReadResourceRequestSchema } from "@modelcontextprotocol/sdk/types.js";
|
package/dist/oauth.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createAuthToken } from "./auth.js";
|
|
2
2
|
import { createAuthCode, decodeAuthCode } from "./crypto.js";
|
|
3
|
-
import { defineHandler, getQuery, redirect } from "h3";
|
|
4
3
|
import { createHash } from "node:crypto";
|
|
4
|
+
import { defineHandler, getQuery, redirect } from "h3";
|
|
5
5
|
//#region src/oauth.ts
|
|
6
6
|
/**
|
|
7
7
|
* OAuth 2.0 endpoints for Claude Desktop integration
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Host-side capability bridge for sandboxed scripts.
|
|
3
|
+
*
|
|
4
|
+
* The QuickJS sandbox has no direct network, filesystem, or process access.
|
|
5
|
+
* The only way a script reaches the Productive API is through this bridge,
|
|
6
|
+
* which re-enters the exact same `executeToolWithCredentials` pipeline used by
|
|
7
|
+
* every other MCP tool call — the real HTTP request happens here, on the host. That means scripts automatically inherit credential scoping, rate
|
|
8
|
+
* limiting, include validation, and formatting — and egress is constrained to
|
|
9
|
+
* the Productive API by construction.
|
|
10
|
+
*
|
|
11
|
+
* The bridge also enforces the per-run API-call budget, honours the run's
|
|
12
|
+
* abort signal (wall-clock timeout), and implements dry-run by classifying
|
|
13
|
+
* mutating operations and recording them instead of executing.
|
|
14
|
+
*/
|
|
15
|
+
import type { ProductiveCredentials } from '../auth.js';
|
|
16
|
+
import type { ToolResult } from '../handlers/types.js';
|
|
17
|
+
import type { RunLimits } from './limits.js';
|
|
18
|
+
/** The subset of `executeToolWithCredentials` the bridge depends on. */
|
|
19
|
+
export type ToolExecutor = (name: string, args: Record<string, unknown>, credentials: ProductiveCredentials) => Promise<ToolResult>;
|
|
20
|
+
/** Logical channels a script may call through. */
|
|
21
|
+
export type BridgeChannel = 'productive' | 'api_read' | 'api_write';
|
|
22
|
+
/** A mutating call recorded (not executed) during a dry run. */
|
|
23
|
+
export interface RecordedCall {
|
|
24
|
+
channel: BridgeChannel;
|
|
25
|
+
payload: Record<string, unknown>;
|
|
26
|
+
}
|
|
27
|
+
export interface BridgeOptions {
|
|
28
|
+
credentials: ProductiveCredentials;
|
|
29
|
+
exec: ToolExecutor;
|
|
30
|
+
limits: RunLimits;
|
|
31
|
+
dryRun: boolean;
|
|
32
|
+
signal: AbortSignal;
|
|
33
|
+
}
|
|
34
|
+
export interface Bridge {
|
|
35
|
+
/**
|
|
36
|
+
* Execute a single bridged call, returning the result as a JSON **string**
|
|
37
|
+
* (the text the tool already produced). Returning text rather than a parsed
|
|
38
|
+
* value lets the engine hand it straight to the guest without an extra
|
|
39
|
+
* parse-then-restringify round trip. Throws on error results so guest-side
|
|
40
|
+
* `try/catch` works naturally.
|
|
41
|
+
*/
|
|
42
|
+
call(channel: BridgeChannel, payload: Record<string, unknown>): Promise<string>;
|
|
43
|
+
/** Snapshot of usage so the handler can report it. */
|
|
44
|
+
getStats(): {
|
|
45
|
+
apiCalls: number;
|
|
46
|
+
recorded: RecordedCall[];
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Create a bridge bound to a set of credentials and limits.
|
|
51
|
+
*/
|
|
52
|
+
export declare function createBridge(opts: BridgeOptions): Bridge;
|
|
53
|
+
//# sourceMappingURL=bridge.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bridge.d.ts","sourceRoot":"","sources":["../../src/run/bridge.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AACxD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAE7C,wEAAwE;AACxE,MAAM,MAAM,YAAY,GAAG,CACzB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,WAAW,EAAE,qBAAqB,KAC/B,OAAO,CAAC,UAAU,CAAC,CAAC;AAEzB,kDAAkD;AAClD,MAAM,MAAM,aAAa,GAAG,YAAY,GAAG,UAAU,GAAG,WAAW,CAAC;AAEpE,gEAAgE;AAChE,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,aAAa,CAAC;IACvB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAClC;AAED,MAAM,WAAW,aAAa;IAC5B,WAAW,EAAE,qBAAqB,CAAC;IACnC,IAAI,EAAE,YAAY,CAAC;IACnB,MAAM,EAAE,SAAS,CAAC;IAClB,MAAM,EAAE,OAAO,CAAC;IAChB,MAAM,EAAE,WAAW,CAAC;CACrB;AAED,MAAM,WAAW,MAAM;IACrB;;;;;;OAMG;IACH,IAAI,CAAC,OAAO,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAChF,sDAAsD;IACtD,QAAQ,IAAI;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,YAAY,EAAE,CAAA;KAAE,CAAC;CAC5D;AA4CD;;GAEG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,aAAa,GAAG,MAAM,CAgCxD"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Scripting-API reference content for `run_script`, surfaced through the global
|
|
3
|
+
* `search_docs` tool (resources / endpoints / scripting all discoverable from
|
|
4
|
+
* one place).
|
|
5
|
+
*
|
|
6
|
+
* This module owns the content as structured sections; `search_docs` is the
|
|
7
|
+
* only consumer (it lists section titles in its table of contents and returns
|
|
8
|
+
* matching section bodies on a query). The resource list is derived from
|
|
9
|
+
* {@link SCRIPT_RESOURCES} so it can't drift from what the prelude exposes.
|
|
10
|
+
*/
|
|
11
|
+
export interface DocSection {
|
|
12
|
+
title: string;
|
|
13
|
+
/** One-line description shown in the table of contents. */
|
|
14
|
+
summary: string;
|
|
15
|
+
keywords: string[];
|
|
16
|
+
body: string;
|
|
17
|
+
}
|
|
18
|
+
export declare const DOC_SECTIONS: DocSection[];
|
|
19
|
+
/** Section titles, for the documentation table of contents. */
|
|
20
|
+
export declare function docSectionTitles(): string[];
|
|
21
|
+
/** Find scripting-doc sections matching a query (title, keywords, or body). */
|
|
22
|
+
export declare function findDocSections(query: string): DocSection[];
|
|
23
|
+
//# sourceMappingURL=docs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"docs.d.ts","sourceRoot":"","sources":["../../src/run/docs.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,2DAA2D;IAC3D,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,eAAO,MAAM,YAAY,EAAE,UAAU,EAwHpC,CAAC;AAEF,+DAA+D;AAC/D,wBAAgB,gBAAgB,IAAI,MAAM,EAAE,CAE3C;AAED,+EAA+E;AAC/E,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU,EAAE,CAS3D"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* QuickJS-WASM execution engine for sandboxed scripts.
|
|
3
|
+
*
|
|
4
|
+
* Each run gets a fresh QuickJS context (isolated globals + heap) created from
|
|
5
|
+
* a single, process-wide cached WASM module. The sandbox has no ambient
|
|
6
|
+
* capabilities: the only host functions exposed are `__hostCall` (bridged API
|
|
7
|
+
* access, returns a real guest Promise so scripts can `await` naturally) and
|
|
8
|
+
* `__emit` (output buffering).
|
|
9
|
+
*
|
|
10
|
+
* Limits enforced here:
|
|
11
|
+
* - memory — `runtime.setMemoryLimit`
|
|
12
|
+
* - CPU/loop — an interrupt handler with a wall-clock deadline (fires even
|
|
13
|
+
* while the host event loop is blocked by a synchronous loop)
|
|
14
|
+
* - hang — an abort-signal race around the async completion wait
|
|
15
|
+
* - output — buffered output is capped and flagged as truncated
|
|
16
|
+
*/
|
|
17
|
+
import { type QuickJSWASMModule } from 'quickjs-emscripten-core';
|
|
18
|
+
import type { RunLimits } from './limits.js';
|
|
19
|
+
/** A single buffered output entry produced by `output.*`. */
|
|
20
|
+
export interface OutputEntry {
|
|
21
|
+
type: string;
|
|
22
|
+
data: unknown;
|
|
23
|
+
}
|
|
24
|
+
/** Successful engine result. */
|
|
25
|
+
export interface EngineResult {
|
|
26
|
+
result: unknown;
|
|
27
|
+
output: OutputEntry[];
|
|
28
|
+
truncated: boolean;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Host call performed on behalf of the guest. Returns the result as a JSON
|
|
32
|
+
* **string** (the text the tool already produced), which is handed straight to
|
|
33
|
+
* the guest without a re-serialization round trip.
|
|
34
|
+
*/
|
|
35
|
+
export type HostCall = (channel: string, payload: Record<string, unknown>) => Promise<string>;
|
|
36
|
+
export interface RunScriptInput {
|
|
37
|
+
code: string;
|
|
38
|
+
args: string[];
|
|
39
|
+
flags: Record<string, unknown>;
|
|
40
|
+
limits: RunLimits;
|
|
41
|
+
signal: AbortSignal;
|
|
42
|
+
hostCall: HostCall;
|
|
43
|
+
}
|
|
44
|
+
/** Error raised when a script fails to compile, throws, or times out. */
|
|
45
|
+
export declare class ScriptError extends Error {
|
|
46
|
+
readonly stackTrace?: string;
|
|
47
|
+
constructor(message: string, stackTrace?: string);
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Lazily create and cache the QuickJS WASM module (decision: cache the
|
|
51
|
+
* compiled module across runs; each run still gets a fresh context).
|
|
52
|
+
*/
|
|
53
|
+
export declare function getQuickJSModule(): Promise<QuickJSWASMModule>;
|
|
54
|
+
/**
|
|
55
|
+
* Run a script to completion in a sandboxed QuickJS context.
|
|
56
|
+
*
|
|
57
|
+
* @throws {ScriptError} on compile error, uncaught guest error, or timeout.
|
|
58
|
+
*/
|
|
59
|
+
export declare function runScript(input: RunScriptInput): Promise<EngineResult>;
|
|
60
|
+
//# sourceMappingURL=engine.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../../src/run/engine.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAGH,OAAO,EAIL,KAAK,iBAAiB,EACvB,MAAM,yBAAyB,CAAC;AAEjC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAI7C,6DAA6D;AAC7D,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,OAAO,CAAC;CACf;AAED,gCAAgC;AAChC,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,OAAO,CAAC;IAChB,MAAM,EAAE,WAAW,EAAE,CAAC;IACtB,SAAS,EAAE,OAAO,CAAC;CACpB;AAED;;;;GAIG;AACH,MAAM,MAAM,QAAQ,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;AAE9F,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,MAAM,EAAE,SAAS,CAAC;IAClB,MAAM,EAAE,WAAW,CAAC;IACpB,QAAQ,EAAE,QAAQ,CAAC;CACpB;AAED,yEAAyE;AACzE,qBAAa,WAAY,SAAQ,KAAK;IACpC,SAAgB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpC,YAAY,OAAO,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,EAI/C;CACF;AAID;;;GAGG;AACH,wBAAgB,gBAAgB,IAAI,OAAO,CAAC,iBAAiB,CAAC,CAK7D;AAyJD;;;;GAIG;AACH,wBAAsB,SAAS,CAAC,KAAK,EAAE,cAAc,GAAG,OAAO,CAAC,YAAY,CAAC,CA6E5E"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resource limits and feature gating for the sandboxed `run_script` tool.
|
|
3
|
+
*
|
|
4
|
+
* The tool is disabled by default and must be explicitly enabled via
|
|
5
|
+
* `PRODUCTIVE_MCP_ENABLE_RUN=true` — same gating model as `api_write`. This
|
|
6
|
+
* keeps hosted HTTP deployments safe until an operator opts in.
|
|
7
|
+
*
|
|
8
|
+
* Every limit is configurable via an environment variable so operators can
|
|
9
|
+
* tune the sandbox for their deployment. Invalid values fall back to the
|
|
10
|
+
* default rather than throwing.
|
|
11
|
+
*/
|
|
12
|
+
/** Resolved resource limits for a single script run. */
|
|
13
|
+
export interface RunLimits {
|
|
14
|
+
/** Wall-clock budget for the whole run, in milliseconds. */
|
|
15
|
+
timeoutMs: number;
|
|
16
|
+
/** Maximum heap the QuickJS runtime may allocate, in bytes. */
|
|
17
|
+
memoryBytes: number;
|
|
18
|
+
/** Maximum number of bridged API calls a single run may make. */
|
|
19
|
+
maxApiCalls: number;
|
|
20
|
+
/** Maximum serialized size of buffered output + result, in bytes. */
|
|
21
|
+
maxOutputBytes: number;
|
|
22
|
+
/** Maximum size of the submitted script source, in bytes. */
|
|
23
|
+
maxCodeBytes: number;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Whether the `run_script` tool is enabled. Off unless explicitly turned on.
|
|
27
|
+
*/
|
|
28
|
+
export declare function isRunScriptEnabled(env?: NodeJS.ProcessEnv): boolean;
|
|
29
|
+
/**
|
|
30
|
+
* Resolve the active resource limits from the environment.
|
|
31
|
+
*/
|
|
32
|
+
export declare function resolveRunLimits(env?: NodeJS.ProcessEnv): RunLimits;
|
|
33
|
+
//# sourceMappingURL=limits.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"limits.d.ts","sourceRoot":"","sources":["../../src/run/limits.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,wDAAwD;AACxD,MAAM,WAAW,SAAS;IACxB,4DAA4D;IAC5D,SAAS,EAAE,MAAM,CAAC;IAClB,+DAA+D;IAC/D,WAAW,EAAE,MAAM,CAAC;IACpB,iEAAiE;IACjE,WAAW,EAAE,MAAM,CAAC;IACpB,qEAAqE;IACrE,cAAc,EAAE,MAAM,CAAC;IACvB,6DAA6D;IAC7D,YAAY,EAAE,MAAM,CAAC;CACtB;AAUD;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,OAAO,CAEhF;AAWD;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,SAAS,CAUhF"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Guest-side JavaScript prelude injected into the sandbox before user code.
|
|
3
|
+
*
|
|
4
|
+
* It builds the `productive`, `api`, `output`, `args`, and `flags` globals on
|
|
5
|
+
* top of two host primitives provided by the engine:
|
|
6
|
+
*
|
|
7
|
+
* - `__hostCall(channel, payloadJson)` → Promise<resultJson> — bridged API call
|
|
8
|
+
* - `__emit(entryJson)` — synchronous output buffering
|
|
9
|
+
*
|
|
10
|
+
* The surface deliberately mirrors the `productive` tool's resource/action
|
|
11
|
+
* model (what agents already know) rather than the fluent SDK, since no SDK
|
|
12
|
+
* code runs inside the sandbox.
|
|
13
|
+
*/
|
|
14
|
+
/** Resources that get a `productive.<resource>` convenience accessor. */
|
|
15
|
+
export declare const SCRIPT_RESOURCES: ("activities" | "attachments" | "batch" | "bookings" | "comments" | "companies" | "custom_fields" | "deals" | "discussions" | "pages" | "people" | "projects" | "reports" | "search" | "services" | "summaries" | "tasks" | "time" | "timers" | "workflows")[];
|
|
16
|
+
export interface PreludeOptions {
|
|
17
|
+
args: string[];
|
|
18
|
+
flags: Record<string, unknown>;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Build the prelude source for a run.
|
|
22
|
+
*
|
|
23
|
+
* `args` and `flags` are embedded as JSON literals (safe — JSON is a subset of
|
|
24
|
+
* JS expression syntax).
|
|
25
|
+
*/
|
|
26
|
+
export declare function buildPrelude(opts: PreludeOptions): string;
|
|
27
|
+
//# sourceMappingURL=prelude.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prelude.d.ts","sourceRoot":"","sources":["../../src/run/prelude.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAWH,yEAAyE;AACzE,eAAO,MAAM,gBAAgB,gQAAsD,CAAC;AAEpF,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAChC;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,cAAc,GAAG,MAAM,CA2DzD"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Remote execution for `run_script`.
|
|
3
|
+
*
|
|
4
|
+
* When `PRODUCTIVE_MCP_RUN_RUNNER_URL` is set, the front server forwards a
|
|
5
|
+
* `run_script` call to a separate runner over a single stateless HTTP POST,
|
|
6
|
+
* instead of executing the QuickJS sandbox in-process. This keeps the front
|
|
7
|
+
* small and isolates a script's memory/CPU (and any OOM) on the runner.
|
|
8
|
+
*
|
|
9
|
+
* The contract is deliberately infrastructure-agnostic — any service that
|
|
10
|
+
* accepts the payload and returns a `ToolResult` works (a Fly machine pool, a
|
|
11
|
+
* load balancer in front of several runners, a serverless function, …). It is
|
|
12
|
+
* stateless (everything needed is in the body) and must NOT be retried at the
|
|
13
|
+
* proxy layer, since a non-dry-run script may mutate.
|
|
14
|
+
*/
|
|
15
|
+
import type { ProductiveCredentials } from '../auth.js';
|
|
16
|
+
import type { ToolResult } from '../handlers/types.js';
|
|
17
|
+
export interface RunnerConfig {
|
|
18
|
+
/** Full URL of the runner's `/run` endpoint (front → runner). */
|
|
19
|
+
url?: string;
|
|
20
|
+
/** Shared secret the runner requires (defends the hop even on private nets). */
|
|
21
|
+
token?: string;
|
|
22
|
+
/** Front-side wall-clock timeout for the whole remote call, in ms. */
|
|
23
|
+
timeoutMs: number;
|
|
24
|
+
}
|
|
25
|
+
/** Request body sent to the runner's `/run` endpoint. */
|
|
26
|
+
export interface RunScriptPayload {
|
|
27
|
+
code: string;
|
|
28
|
+
args: string[];
|
|
29
|
+
flags: Record<string, unknown>;
|
|
30
|
+
dry_run: boolean;
|
|
31
|
+
credentials: ProductiveCredentials;
|
|
32
|
+
}
|
|
33
|
+
/** Resolve runner configuration from the environment. */
|
|
34
|
+
export declare function resolveRunnerConfig(env?: NodeJS.ProcessEnv): RunnerConfig;
|
|
35
|
+
/** Whether this server should forward run_script to a remote runner. */
|
|
36
|
+
export declare function isRemoteRunner(env?: NodeJS.ProcessEnv): boolean;
|
|
37
|
+
/** Constant-time comparison of a provided runner token against the expected one. */
|
|
38
|
+
export declare function runnerTokenMatches(provided: string | undefined, expected: string | undefined): boolean;
|
|
39
|
+
/**
|
|
40
|
+
* Forward a run_script call to the remote runner. Never throws: any transport
|
|
41
|
+
* or runner error is mapped to an error `ToolResult`.
|
|
42
|
+
*/
|
|
43
|
+
export declare function runScriptRemote(payload: RunScriptPayload, config: RunnerConfig, fetchImpl?: typeof fetch): Promise<ToolResult>;
|
|
44
|
+
//# sourceMappingURL=remote.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"remote.d.ts","sourceRoot":"","sources":["../../src/run/remote.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAIH,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AACxD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAIvD,MAAM,WAAW,YAAY;IAC3B,iEAAiE;IACjE,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,gFAAgF;IAChF,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,sEAAsE;IACtE,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,yDAAyD;AACzD,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,EAAE,qBAAqB,CAAC;CACpC;AAID,yDAAyD;AACzD,wBAAgB,mBAAmB,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,YAAY,CAStF;AAED,wEAAwE;AACxE,wBAAgB,cAAc,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,OAAO,CAE5E;AAED,oFAAoF;AACpF,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,MAAM,GAAG,SAAS,EAC5B,QAAQ,EAAE,MAAM,GAAG,SAAS,GAC3B,OAAO,CAMT;AAED;;;GAGG;AACH,wBAAsB,eAAe,CACnC,OAAO,EAAE,gBAAgB,EACzB,MAAM,EAAE,YAAY,EACpB,SAAS,GAAE,OAAO,KAAa,GAC9B,OAAO,CAAC,UAAU,CAAC,CAqCrB"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Markdown rendering for `run_script` results.
|
|
3
|
+
*
|
|
4
|
+
* The tool returns two things (per the MCP structured-output convention):
|
|
5
|
+
* - `structuredContent` — the raw `{ result, output, _run }` object for hosts
|
|
6
|
+
* that consume structured tool output;
|
|
7
|
+
* - a `text` content block — this human-facing Markdown rendering, so clients
|
|
8
|
+
* that only display text still get formatted tables/JSON/logs rather than a
|
|
9
|
+
* single opaque JSON blob.
|
|
10
|
+
*
|
|
11
|
+
* MCP has no "table" content type, so "rendering" here means producing Markdown
|
|
12
|
+
* (tables, fenced code blocks, labelled lines).
|
|
13
|
+
*/
|
|
14
|
+
import type { OutputEntry } from './engine.js';
|
|
15
|
+
export interface RunStats {
|
|
16
|
+
apiCalls: number;
|
|
17
|
+
dryRun: boolean;
|
|
18
|
+
outputTruncated?: boolean;
|
|
19
|
+
recorded?: unknown[];
|
|
20
|
+
}
|
|
21
|
+
export interface RunRenderInput {
|
|
22
|
+
result: unknown;
|
|
23
|
+
output: OutputEntry[];
|
|
24
|
+
run: RunStats;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Render a run result as human-facing Markdown.
|
|
28
|
+
*/
|
|
29
|
+
export declare function renderRunResult(input: RunRenderInput): string;
|
|
30
|
+
//# sourceMappingURL=render.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../../src/run/render.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C,MAAM,WAAW,QAAQ;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,OAAO,CAAC;IAChB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,EAAE,OAAO,EAAE,CAAC;CACtB;AAED,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,OAAO,CAAC;IAChB,MAAM,EAAE,WAAW,EAAE,CAAC;IACtB,GAAG,EAAE,QAAQ,CAAC;CACf;AA4FD;;GAEG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,cAAc,GAAG,MAAM,CAqB7D"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TypeScript type-stripping for submitted scripts.
|
|
3
|
+
*
|
|
4
|
+
* QuickJS executes JavaScript, so any TypeScript syntax in a submitted script
|
|
5
|
+
* must be transformed away first. We use Node's built-in
|
|
6
|
+
* {@link stripTypeScriptTypes} in `transform` mode, which also lowers `enum`
|
|
7
|
+
* and parameter properties (not just erasing annotations).
|
|
8
|
+
*
|
|
9
|
+
* Plain JavaScript passes through unchanged. If the source cannot be parsed as
|
|
10
|
+
* TypeScript at all, the original is returned untouched so the sandbox can
|
|
11
|
+
* surface the real syntax error to the caller.
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* Strip TypeScript types from a script, returning runnable JavaScript.
|
|
15
|
+
*
|
|
16
|
+
* @param code - The submitted script source (TypeScript or JavaScript).
|
|
17
|
+
* @returns JavaScript with type syntax removed.
|
|
18
|
+
*/
|
|
19
|
+
export declare function stripTypes(code: string): string;
|
|
20
|
+
//# sourceMappingURL=strip.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"strip.d.ts","sourceRoot":"","sources":["../../src/run/strip.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAIH;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAQ/C"}
|
package/dist/schema.d.ts
CHANGED
|
@@ -265,7 +265,8 @@ export type ProductiveToolInput = z.infer<typeof ProductiveToolInputSchema>;
|
|
|
265
265
|
* Full input schema for the raw api_read tool.
|
|
266
266
|
*/
|
|
267
267
|
export declare const ApiReadToolInputSchema: z.ZodObject<{
|
|
268
|
-
path: z.ZodString
|
|
268
|
+
path: z.ZodOptional<z.ZodString>;
|
|
269
|
+
search: z.ZodOptional<z.ZodString>;
|
|
269
270
|
describe: z.ZodOptional<z.ZodBoolean>;
|
|
270
271
|
filter: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
271
272
|
include: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
@@ -292,6 +293,16 @@ export declare const ApiWriteToolInputSchema: z.ZodObject<{
|
|
|
292
293
|
dry_run: z.ZodOptional<z.ZodBoolean>;
|
|
293
294
|
}, z.core.$strip>;
|
|
294
295
|
export type ApiWriteToolInput = z.infer<typeof ApiWriteToolInputSchema>;
|
|
296
|
+
/**
|
|
297
|
+
* Full input schema for the sandboxed run_script tool.
|
|
298
|
+
*/
|
|
299
|
+
export declare const RunScriptToolInputSchema: z.ZodObject<{
|
|
300
|
+
code: z.ZodString;
|
|
301
|
+
args: z.ZodOptional<z.ZodArray<z.ZodUnknown>>;
|
|
302
|
+
flags: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
303
|
+
dry_run: z.ZodOptional<z.ZodBoolean>;
|
|
304
|
+
}, z.core.$strip>;
|
|
305
|
+
export type RunScriptToolInput = z.infer<typeof RunScriptToolInputSchema>;
|
|
295
306
|
/**
|
|
296
307
|
* Validate and parse tool input
|
|
297
308
|
* Returns parsed data or throws with validation errors
|
|
@@ -305,5 +316,5 @@ export declare function safeValidateToolInput(input: unknown): ZodSafeParseResul
|
|
|
305
316
|
/**
|
|
306
317
|
* Format Zod validation errors for LLM consumption
|
|
307
318
|
*/
|
|
308
|
-
export declare function formatValidationErrors(error: ZodError<ProductiveToolInput | ApiReadToolInput | ApiWriteToolInput>): string;
|
|
319
|
+
export declare function formatValidationErrors(error: ZodError<ProductiveToolInput | ApiReadToolInput | ApiWriteToolInput | RunScriptToolInput>): string;
|
|
309
320
|
//# sourceMappingURL=schema.d.ts.map
|
package/dist/schema.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,EAAE,CAAC,EAAoB,KAAK,kBAAkB,EAAE,KAAK,QAAQ,EAAE,MAAM,KAAK,CAAC;AAGlF,YAAY,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAMhF;;;GAGG;AACH,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;EAAoB,CAAC;AAEhD;;;GAGG;AACH,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;EAAkB,CAAC;AAE5C;;;GAGG;AACH,eAAO,MAAM,gBAAgB;;;;;;;;;;;;EAAuB,CAAC;AAMrD;;GAEG;AACH,eAAO,MAAM,OAAO,aAIgC,CAAC;AAErD;;GAEG;AACH,eAAO,MAAM,aAAa,aAKvB,CAAC;AAEJ;;GAEG;AACH,eAAO,MAAM,cAAc,aAKxB,CAAC;AAEJ;;GAEG;AACH,eAAO,MAAM,cAAc,aAGqD,CAAC;AAEjF;;GAEG;AACH,eAAO,MAAM,WAAW,aAG+C,CAAC;AAExE;;GAEG;AACH,eAAO,MAAM,cAAc,aAGuD,CAAC;AAEnF;;GAEG;AACH,eAAO,MAAM,WAAW,aAG+C,CAAC;AAExE;;GAEG;AACH,eAAO,MAAM,SAAS,aAIuC,CAAC;AAE9D;;GAEG;AACH,eAAO,MAAM,gBAAgB,aAKiE,CAAC;AAE/F;;GAEG;AACH,eAAO,MAAM,SAAS,2BAKiC,CAAC;AAExD;;GAEG;AACH,eAAO,MAAM,YAAY,2BAMsC,CAAC;AAEhE;;GAEG;AACH,eAAO,MAAM,YAAY,6BAKtB,CAAC;AAEJ;;GAEG;AACH,eAAO,MAAM,UAAU,aAMpB,CAAC;AAEJ;;GAEG;AACH,eAAO,MAAM,cAAc,wCAKxB,CAAC;AAEJ;;GAEG;AACH,eAAO,MAAM,YAAY,6BAKtB,CAAC;AAEJ;;GAEG;AACH,eAAO,MAAM,YAAY,yBAItB,CAAC;AAEJ;;GAEG;AACH,eAAO,MAAM,SAAS,aAAkD,CAAC;AAEzE;;GAEG;AACH,eAAO,MAAM,UAAU,aAIqB,CAAC;AAE7C;;GAEG;AACH,eAAO,MAAM,SAAS,aAGgB,CAAC;AAMvC;;GAEG;AACH,eAAO,MAAM,YAAY,uDAGsB,CAAC;AAMhD;;;GAGG;AACH,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAqFpC,CAAC;AAEH,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAC;AAE5E;;GAEG;AACH,eAAO,MAAM,sBAAsB
|
|
1
|
+
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"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"}
|
package/dist/server.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { t as VERSION } from "./version-
|
|
3
|
-
import { t as createHttpApp } from "./http-
|
|
2
|
+
import { t as VERSION } from "./version-Jj_0Ypf8.js";
|
|
3
|
+
import { t as createHttpApp } from "./http-xNZOdN_t.js";
|
|
4
4
|
import { toNodeHandler } from "h3";
|
|
5
5
|
import { createServer } from "node:http";
|
|
6
6
|
//#region src/server.ts
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as executeToolWithCredentials } from "./handlers-
|
|
1
|
+
import { t as executeToolWithCredentials } from "./handlers-Ca2x4dM8.js";
|
|
2
2
|
import { STDIO_ONLY_TOOLS, TOOLS } from "./tools.js";
|
|
3
3
|
import { getConfig, setConfig } from "@studiometa/productive-api";
|
|
4
4
|
//#region src/prompts/definitions.ts
|
|
@@ -354,4 +354,4 @@ async function handlePrompt(name, args) {
|
|
|
354
354
|
//#endregion
|
|
355
355
|
export { handlePrompt as a, handleGetConfigTool as i, getAvailableTools as n, handleSetupPrompt as o, handleConfigureTool as r, handleToolCall as s, getAvailablePrompts as t };
|
|
356
356
|
|
|
357
|
-
//# sourceMappingURL=stdio-
|
|
357
|
+
//# sourceMappingURL=stdio-jqfOnE6-.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stdio-BnfO285Q.js","names":[],"sources":["../src/prompts/definitions.ts","../src/prompts/handlers.ts","../src/stdio.ts"],"sourcesContent":["/**\n * MCP Prompt Template Definitions\n *\n * Prompt templates serve as guided conversation starters that instruct the LLM\n * which productive tool calls to make and how to format the output.\n */\n\nexport interface PromptArgument {\n name: string;\n description: string;\n required: boolean;\n}\n\nexport interface PromptDefinition {\n name: string;\n description: string;\n arguments: PromptArgument[];\n}\n\nexport const PROMPT_DEFINITIONS: PromptDefinition[] = [\n {\n name: 'end-of-day',\n description: 'Compose an end-of-day standup message based on your activity today',\n arguments: [\n {\n name: 'format',\n description: 'Output format: slack, email, or plain (default: plain)',\n required: false,\n },\n ],\n },\n {\n name: 'project-review',\n description: 'Analyze project health and status with budget, tasks, and timeline overview',\n arguments: [\n {\n name: 'project',\n description: 'Project ID or project number (e.g. PRJ-123)',\n required: true,\n },\n ],\n },\n {\n name: 'plan-sprint',\n description: 'Help prioritize tasks for the next sprint based on open tasks and budget',\n arguments: [\n {\n name: 'project',\n description: 'Project ID or project number (e.g. PRJ-123)',\n required: true,\n },\n ],\n },\n {\n name: 'weekly-report',\n description: 'Generate a polished weekly progress report',\n arguments: [\n {\n name: 'person',\n description: 'Person email or ID to report on (default: current user)',\n required: false,\n },\n {\n name: 'format',\n description: 'Output format: slack, email, or plain (default: plain)',\n required: false,\n },\n ],\n },\n {\n name: 'invoice-prep',\n description: 'Prepare a billing summary for a project within a date range',\n arguments: [\n {\n name: 'project',\n description: 'Project ID or project number (e.g. PRJ-123)',\n required: true,\n },\n {\n name: 'from',\n description: 'Start date in YYYY-MM-DD format',\n required: true,\n },\n {\n name: 'to',\n description: 'End date in YYYY-MM-DD format',\n required: true,\n },\n ],\n },\n];\n","/**\n * MCP Prompt Template Handlers\n *\n * Returns messages arrays that instruct the LLM which productive tool calls to\n * make and how to format and present the output to the user.\n */\n\ntype PromptMessage = {\n role: string;\n content: { type: string; text: string };\n};\n\ntype PromptResult = {\n messages: PromptMessage[];\n};\n\n/**\n * Build the end-of-day standup prompt messages\n */\nfunction endOfDay(args?: Record<string, string>): PromptResult {\n const format = args?.format ?? 'plain';\n\n const formatInstruction =\n format === 'slack'\n ? 'Format the output as a Slack message using emoji bullets and bold text with *asterisks*.'\n : format === 'email'\n ? 'Format the output as a professional email with a subject line and proper greeting/closing.'\n : 'Format the output as a plain-text standup message with clear sections.';\n\n return {\n messages: [\n {\n role: 'user',\n content: {\n type: 'text',\n text: `Please compose my end-of-day standup message.\n\nFirst, call the productive tool to gather today's activity:\n\\`\\`\\`json\n{ \"resource\": \"summaries\", \"action\": \"my_day\" }\n\\`\\`\\`\n\nThen compose a standup message with these sections:\n- **What I did today**: Summarize completed tasks and logged time by project\n- **What I'm working on tomorrow**: Any open/in-progress tasks from today\n- **Blockers**: Note any overdue tasks or items needing attention\n\n${formatInstruction}\n\nKeep it concise — this is for a standup, not a novel.`,\n },\n },\n ],\n };\n}\n\n/**\n * Build the project-review prompt messages\n */\nfunction projectReview(args?: Record<string, string>): PromptResult {\n const project = args?.project ?? '';\n\n return {\n messages: [\n {\n role: 'user',\n content: {\n type: 'text',\n text: `Please analyze the health and status of project ${project ? `\"${project}\"` : '(project not specified)'}.\n\nFetch all project context in one call:\n\\`\\`\\`json\n{ \"resource\": \"projects\", \"action\": \"context\", \"id\": \"${project}\" }\n\\`\\`\\`\n\nAlso check the project's tasks for a fuller picture:\n\\`\\`\\`json\n{ \"resource\": \"tasks\", \"action\": \"list\", \"filter\": { \"project_id\": \"${project}\", \"status\": 1 }, \"per_page\": 50 }\n\\`\\`\\`\n\nThen provide a structured project health review covering:\n1. **Overview**: Project name, client, current status\n2. **Budget**: Budget used vs total, burn rate, projected overage risk\n3. **Tasks**: Open vs completed task counts, overdue tasks, upcoming deadlines\n4. **Recent activity**: What has been worked on recently\n5. **Health assessment**: Overall RAG status (🟢 On track / 🟡 At risk / 🔴 Critical) with reasoning\n6. **Recommendations**: Concrete next steps or concerns to address`,\n },\n },\n ],\n };\n}\n\n/**\n * Build the plan-sprint prompt messages\n */\nfunction planSprint(args?: Record<string, string>): PromptResult {\n const project = args?.project ?? '';\n\n return {\n messages: [\n {\n role: 'user',\n content: {\n type: 'text',\n text: `Please help me plan the next sprint for project ${project ? `\"${project}\"` : '(project not specified)'}.\n\nFetch all open tasks for the project:\n\\`\\`\\`json\n{ \"resource\": \"tasks\", \"action\": \"list\", \"filter\": { \"project_id\": \"${project}\", \"status\": 1 }, \"per_page\": 100 }\n\\`\\`\\`\n\nFetch the project's budget services to understand available capacity:\n\\`\\`\\`json\n{ \"resource\": \"services\", \"action\": \"list\", \"filter\": { \"project_id\": \"${project}\" }, \"per_page\": 50 }\n\\`\\`\\`\n\nThen provide sprint planning recommendations:\n1. **Backlog summary**: Total open tasks, categories/task-lists breakdown\n2. **Priority candidates**: Top tasks to tackle next sprint based on:\n - Due dates and overdue items\n - Task dependencies (if visible)\n - Effort estimates\n3. **Budget check**: Remaining budget per service — flag if any service is near its limit\n4. **Suggested sprint scope**: A realistic list of tasks for a 1-2 week sprint\n5. **Risks**: Tasks that are blocked, unassigned, or missing estimates`,\n },\n },\n ],\n };\n}\n\n/**\n * Build the weekly-report prompt messages\n */\nfunction weeklyReport(args?: Record<string, string>): PromptResult {\n const person = args?.person;\n const format = args?.format ?? 'plain';\n\n const personInstruction = person\n ? `Focus on person \"${person}\". Resolve the person ID if needed using: { \"resource\": \"people\", \"action\": \"resolve\", \"query\": \"${person}\" } first.`\n : 'Focus on the current authenticated user (use the default person from summaries).';\n\n const formatInstruction =\n format === 'slack'\n ? 'Format as a Slack message with emoji bullets, bold project names, and a summary header.'\n : format === 'email'\n ? 'Format as a professional email with subject line, greeting, bulleted highlights per project, and a closing.'\n : 'Format as a clean plain-text weekly report with clear section headers.';\n\n const standupCall = person\n ? `First resolve the person ID, then fetch weekly standup data:\n\\`\\`\\`json\n{ \"resource\": \"people\", \"action\": \"resolve\", \"query\": \"${person}\" }\n\\`\\`\\`\n\\`\\`\\`json\n{ \"resource\": \"workflows\", \"action\": \"weekly_standup\", \"person_id\": \"<resolved_person_id>\" }\n\\`\\`\\``\n : `Fetch weekly standup data:\n\\`\\`\\`json\n{ \"resource\": \"workflows\", \"action\": \"weekly_standup\" }\n\\`\\`\\``;\n\n return {\n messages: [\n {\n role: 'user',\n content: {\n type: 'text',\n text: `Please generate a weekly progress report.\n\n${personInstruction}\n\n${standupCall}\n\nThen compose a polished weekly report with:\n1. **This week's accomplishments**: Completed tasks grouped by project\n2. **Time logged**: Hours per project this week, total hours\n3. **In progress**: Tasks still open that were worked on\n4. **Upcoming**: Any tasks with deadlines in the next 7 days\n5. **Highlights**: Notable wins or milestones reached\n\n${formatInstruction}`,\n },\n },\n ],\n };\n}\n\n/**\n * Build the invoice-prep prompt messages\n */\nfunction invoicePrep(args?: Record<string, string>): PromptResult {\n const project = args?.project ?? '';\n const from = args?.from ?? '';\n const to = args?.to ?? '';\n\n return {\n messages: [\n {\n role: 'user',\n content: {\n type: 'text',\n text: `Please prepare a billing summary for project ${project ? `\"${project}\"` : '(project not specified)'} from ${from || '(start date not specified)'} to ${to || '(end date not specified)'}.\n\nFetch time entries for the date range:\n\\`\\`\\`json\n{\n \"resource\": \"time\",\n \"action\": \"list\",\n \"filter\": {\n \"project_id\": \"${project}\",\n \"after\": \"${from}\",\n \"before\": \"${to}\"\n },\n \"include\": [\"person\", \"service\"],\n \"per_page\": 200\n}\n\\`\\`\\`\n\nFetch project services/budget lines:\n\\`\\`\\`json\n{ \"resource\": \"services\", \"action\": \"list\", \"filter\": { \"project_id\": \"${project}\" }, \"per_page\": 50 }\n\\`\\`\\`\n\nFetch the project deal/budget details:\n\\`\\`\\`json\n{ \"resource\": \"deals\", \"action\": \"list\", \"filter\": { \"project_id\": \"${project}\", \"type\": 2 }, \"per_page\": 10 }\n\\`\\`\\`\n\nThen produce a billing summary:\n1. **Period**: ${from} → ${to}\n2. **Time entries by service**: Hours logged per service/budget line with team member breakdown\n3. **Billable totals**: If rates are available, calculate amounts per service\n4. **Budget consumed**: Planned vs actual hours per service\n5. **Invoice line items**: Suggested line items ready to copy into an invoice\n6. **Notes**: Any unbilled items, write-offs, or adjustments to flag`,\n },\n },\n ],\n };\n}\n\n/**\n * Get messages for a named prompt template\n */\nexport function getPromptMessages(name: string, args?: Record<string, string>): PromptResult {\n switch (name) {\n case 'end-of-day':\n return endOfDay(args);\n case 'project-review':\n return projectReview(args);\n case 'plan-sprint':\n return planSprint(args);\n case 'weekly-report':\n return weeklyReport(args);\n case 'invoice-prep':\n return invoicePrep(args);\n default:\n throw new Error(`Unknown prompt: ${name}`);\n }\n}\n","/**\n * Stdio transport handlers for Productive MCP Server\n *\n * This module contains the handler logic for the stdio transport.\n * The actual server startup is in index.ts.\n */\n\nimport type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';\n\nimport { getConfig, setConfig } from '@studiometa/productive-api';\n\nimport { executeToolWithCredentials } from './handlers.js';\nimport { PROMPT_DEFINITIONS, getPromptMessages } from './prompts/index.js';\nimport { TOOLS, STDIO_ONLY_TOOLS } from './tools.js';\n\nexport type ToolResult = CallToolResult;\n\n/**\n * Get all available tools (including stdio-only configuration tools)\n */\nexport function getAvailableTools() {\n return [...TOOLS, ...STDIO_ONLY_TOOLS];\n}\n\n/**\n * Get available prompts\n */\nexport function getAvailablePrompts() {\n return [\n {\n name: 'setup_productive',\n description: 'Interactive setup for Productive.io credentials',\n arguments: [],\n },\n ...PROMPT_DEFINITIONS,\n ];\n}\n\n/**\n * Handle the setup_productive prompt\n */\nexport async function handleSetupPrompt(): Promise<{\n messages: Array<{ role: string; content: { type: string; text: string } }>;\n}> {\n const config = await getConfig();\n const hasConfig = !!(config.organizationId && config.apiToken);\n\n return {\n messages: [\n {\n role: 'user',\n content: {\n type: 'text',\n text: hasConfig\n ? 'I have already configured Productive.io credentials. Would you like to update them?'\n : 'I need to configure my Productive.io credentials. Please help me set up:\\n1. Organization ID\\n2. API Token\\n3. User ID (optional)',\n },\n },\n ],\n };\n}\n\n/**\n * Handle the productive_configure tool\n */\nexport async function handleConfigureTool(args: {\n organizationId: string;\n apiToken: string;\n userId?: string;\n}): Promise<ToolResult> {\n const { organizationId, apiToken, userId } = args;\n\n await setConfig('organizationId', organizationId);\n await setConfig('apiToken', apiToken);\n if (userId) {\n await setConfig('userId', userId);\n }\n\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify(\n {\n success: true,\n message: 'Productive.io credentials configured successfully',\n configured: {\n organizationId,\n userId: userId || 'not set',\n apiToken: '***' + apiToken.slice(-4),\n },\n },\n null,\n 2,\n ),\n },\n ],\n };\n}\n\n/**\n * Handle the productive_get_config tool\n */\nexport async function handleGetConfigTool(): Promise<ToolResult> {\n const currentConfig = await getConfig();\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify(\n {\n organizationId: currentConfig.organizationId || 'not configured',\n userId: currentConfig.userId || 'not configured',\n apiToken: currentConfig.apiToken\n ? '***' + currentConfig.apiToken.slice(-4)\n : 'not configured',\n configured: !!(currentConfig.organizationId && currentConfig.apiToken),\n },\n null,\n 2,\n ),\n },\n ],\n };\n}\n\n/**\n * Handle a tool call request\n */\nexport async function handleToolCall(\n name: string,\n args: Record<string, unknown>,\n): Promise<ToolResult> {\n // Handle stdio-only configuration tools\n if (name === 'productive_configure') {\n return handleConfigureTool(args as Parameters<typeof handleConfigureTool>[0]);\n }\n\n if (name === 'productive_get_config') {\n return handleGetConfigTool();\n }\n\n // Get config for API tools\n const config = await getConfig();\n if (!config.organizationId || !config.apiToken) {\n return {\n content: [\n {\n type: 'text',\n text: 'Error: Productive.io credentials not configured. Please use the \"productive_configure\" tool to set your credentials, or set PRODUCTIVE_ORG_ID and PRODUCTIVE_API_TOKEN environment variables.',\n },\n ],\n isError: true,\n };\n }\n\n // Execute tool with credentials from config\n return executeToolWithCredentials(name, args, {\n organizationId: config.organizationId,\n apiToken: config.apiToken,\n userId: config.userId,\n });\n}\n\n/**\n * Handle a prompt request\n */\nexport async function handlePrompt(\n name: string,\n args?: Record<string, string>,\n): Promise<{\n messages: Array<{ role: string; content: { type: string; text: string } }>;\n}> {\n if (name === 'setup_productive') {\n return handleSetupPrompt();\n }\n\n return getPromptMessages(name, args);\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"stdio-jqfOnE6-.js","names":[],"sources":["../src/prompts/definitions.ts","../src/prompts/handlers.ts","../src/stdio.ts"],"sourcesContent":["/**\n * MCP Prompt Template Definitions\n *\n * Prompt templates serve as guided conversation starters that instruct the LLM\n * which productive tool calls to make and how to format the output.\n */\n\nexport interface PromptArgument {\n name: string;\n description: string;\n required: boolean;\n}\n\nexport interface PromptDefinition {\n name: string;\n description: string;\n arguments: PromptArgument[];\n}\n\nexport const PROMPT_DEFINITIONS: PromptDefinition[] = [\n {\n name: 'end-of-day',\n description: 'Compose an end-of-day standup message based on your activity today',\n arguments: [\n {\n name: 'format',\n description: 'Output format: slack, email, or plain (default: plain)',\n required: false,\n },\n ],\n },\n {\n name: 'project-review',\n description: 'Analyze project health and status with budget, tasks, and timeline overview',\n arguments: [\n {\n name: 'project',\n description: 'Project ID or project number (e.g. PRJ-123)',\n required: true,\n },\n ],\n },\n {\n name: 'plan-sprint',\n description: 'Help prioritize tasks for the next sprint based on open tasks and budget',\n arguments: [\n {\n name: 'project',\n description: 'Project ID or project number (e.g. PRJ-123)',\n required: true,\n },\n ],\n },\n {\n name: 'weekly-report',\n description: 'Generate a polished weekly progress report',\n arguments: [\n {\n name: 'person',\n description: 'Person email or ID to report on (default: current user)',\n required: false,\n },\n {\n name: 'format',\n description: 'Output format: slack, email, or plain (default: plain)',\n required: false,\n },\n ],\n },\n {\n name: 'invoice-prep',\n description: 'Prepare a billing summary for a project within a date range',\n arguments: [\n {\n name: 'project',\n description: 'Project ID or project number (e.g. PRJ-123)',\n required: true,\n },\n {\n name: 'from',\n description: 'Start date in YYYY-MM-DD format',\n required: true,\n },\n {\n name: 'to',\n description: 'End date in YYYY-MM-DD format',\n required: true,\n },\n ],\n },\n];\n","/**\n * MCP Prompt Template Handlers\n *\n * Returns messages arrays that instruct the LLM which productive tool calls to\n * make and how to format and present the output to the user.\n */\n\ntype PromptMessage = {\n role: string;\n content: { type: string; text: string };\n};\n\ntype PromptResult = {\n messages: PromptMessage[];\n};\n\n/**\n * Build the end-of-day standup prompt messages\n */\nfunction endOfDay(args?: Record<string, string>): PromptResult {\n const format = args?.format ?? 'plain';\n\n const formatInstruction =\n format === 'slack'\n ? 'Format the output as a Slack message using emoji bullets and bold text with *asterisks*.'\n : format === 'email'\n ? 'Format the output as a professional email with a subject line and proper greeting/closing.'\n : 'Format the output as a plain-text standup message with clear sections.';\n\n return {\n messages: [\n {\n role: 'user',\n content: {\n type: 'text',\n text: `Please compose my end-of-day standup message.\n\nFirst, call the productive tool to gather today's activity:\n\\`\\`\\`json\n{ \"resource\": \"summaries\", \"action\": \"my_day\" }\n\\`\\`\\`\n\nThen compose a standup message with these sections:\n- **What I did today**: Summarize completed tasks and logged time by project\n- **What I'm working on tomorrow**: Any open/in-progress tasks from today\n- **Blockers**: Note any overdue tasks or items needing attention\n\n${formatInstruction}\n\nKeep it concise — this is for a standup, not a novel.`,\n },\n },\n ],\n };\n}\n\n/**\n * Build the project-review prompt messages\n */\nfunction projectReview(args?: Record<string, string>): PromptResult {\n const project = args?.project ?? '';\n\n return {\n messages: [\n {\n role: 'user',\n content: {\n type: 'text',\n text: `Please analyze the health and status of project ${project ? `\"${project}\"` : '(project not specified)'}.\n\nFetch all project context in one call:\n\\`\\`\\`json\n{ \"resource\": \"projects\", \"action\": \"context\", \"id\": \"${project}\" }\n\\`\\`\\`\n\nAlso check the project's tasks for a fuller picture:\n\\`\\`\\`json\n{ \"resource\": \"tasks\", \"action\": \"list\", \"filter\": { \"project_id\": \"${project}\", \"status\": 1 }, \"per_page\": 50 }\n\\`\\`\\`\n\nThen provide a structured project health review covering:\n1. **Overview**: Project name, client, current status\n2. **Budget**: Budget used vs total, burn rate, projected overage risk\n3. **Tasks**: Open vs completed task counts, overdue tasks, upcoming deadlines\n4. **Recent activity**: What has been worked on recently\n5. **Health assessment**: Overall RAG status (🟢 On track / 🟡 At risk / 🔴 Critical) with reasoning\n6. **Recommendations**: Concrete next steps or concerns to address`,\n },\n },\n ],\n };\n}\n\n/**\n * Build the plan-sprint prompt messages\n */\nfunction planSprint(args?: Record<string, string>): PromptResult {\n const project = args?.project ?? '';\n\n return {\n messages: [\n {\n role: 'user',\n content: {\n type: 'text',\n text: `Please help me plan the next sprint for project ${project ? `\"${project}\"` : '(project not specified)'}.\n\nFetch all open tasks for the project:\n\\`\\`\\`json\n{ \"resource\": \"tasks\", \"action\": \"list\", \"filter\": { \"project_id\": \"${project}\", \"status\": 1 }, \"per_page\": 100 }\n\\`\\`\\`\n\nFetch the project's budget services to understand available capacity:\n\\`\\`\\`json\n{ \"resource\": \"services\", \"action\": \"list\", \"filter\": { \"project_id\": \"${project}\" }, \"per_page\": 50 }\n\\`\\`\\`\n\nThen provide sprint planning recommendations:\n1. **Backlog summary**: Total open tasks, categories/task-lists breakdown\n2. **Priority candidates**: Top tasks to tackle next sprint based on:\n - Due dates and overdue items\n - Task dependencies (if visible)\n - Effort estimates\n3. **Budget check**: Remaining budget per service — flag if any service is near its limit\n4. **Suggested sprint scope**: A realistic list of tasks for a 1-2 week sprint\n5. **Risks**: Tasks that are blocked, unassigned, or missing estimates`,\n },\n },\n ],\n };\n}\n\n/**\n * Build the weekly-report prompt messages\n */\nfunction weeklyReport(args?: Record<string, string>): PromptResult {\n const person = args?.person;\n const format = args?.format ?? 'plain';\n\n const personInstruction = person\n ? `Focus on person \"${person}\". Resolve the person ID if needed using: { \"resource\": \"people\", \"action\": \"resolve\", \"query\": \"${person}\" } first.`\n : 'Focus on the current authenticated user (use the default person from summaries).';\n\n const formatInstruction =\n format === 'slack'\n ? 'Format as a Slack message with emoji bullets, bold project names, and a summary header.'\n : format === 'email'\n ? 'Format as a professional email with subject line, greeting, bulleted highlights per project, and a closing.'\n : 'Format as a clean plain-text weekly report with clear section headers.';\n\n const standupCall = person\n ? `First resolve the person ID, then fetch weekly standup data:\n\\`\\`\\`json\n{ \"resource\": \"people\", \"action\": \"resolve\", \"query\": \"${person}\" }\n\\`\\`\\`\n\\`\\`\\`json\n{ \"resource\": \"workflows\", \"action\": \"weekly_standup\", \"person_id\": \"<resolved_person_id>\" }\n\\`\\`\\``\n : `Fetch weekly standup data:\n\\`\\`\\`json\n{ \"resource\": \"workflows\", \"action\": \"weekly_standup\" }\n\\`\\`\\``;\n\n return {\n messages: [\n {\n role: 'user',\n content: {\n type: 'text',\n text: `Please generate a weekly progress report.\n\n${personInstruction}\n\n${standupCall}\n\nThen compose a polished weekly report with:\n1. **This week's accomplishments**: Completed tasks grouped by project\n2. **Time logged**: Hours per project this week, total hours\n3. **In progress**: Tasks still open that were worked on\n4. **Upcoming**: Any tasks with deadlines in the next 7 days\n5. **Highlights**: Notable wins or milestones reached\n\n${formatInstruction}`,\n },\n },\n ],\n };\n}\n\n/**\n * Build the invoice-prep prompt messages\n */\nfunction invoicePrep(args?: Record<string, string>): PromptResult {\n const project = args?.project ?? '';\n const from = args?.from ?? '';\n const to = args?.to ?? '';\n\n return {\n messages: [\n {\n role: 'user',\n content: {\n type: 'text',\n text: `Please prepare a billing summary for project ${project ? `\"${project}\"` : '(project not specified)'} from ${from || '(start date not specified)'} to ${to || '(end date not specified)'}.\n\nFetch time entries for the date range:\n\\`\\`\\`json\n{\n \"resource\": \"time\",\n \"action\": \"list\",\n \"filter\": {\n \"project_id\": \"${project}\",\n \"after\": \"${from}\",\n \"before\": \"${to}\"\n },\n \"include\": [\"person\", \"service\"],\n \"per_page\": 200\n}\n\\`\\`\\`\n\nFetch project services/budget lines:\n\\`\\`\\`json\n{ \"resource\": \"services\", \"action\": \"list\", \"filter\": { \"project_id\": \"${project}\" }, \"per_page\": 50 }\n\\`\\`\\`\n\nFetch the project deal/budget details:\n\\`\\`\\`json\n{ \"resource\": \"deals\", \"action\": \"list\", \"filter\": { \"project_id\": \"${project}\", \"type\": 2 }, \"per_page\": 10 }\n\\`\\`\\`\n\nThen produce a billing summary:\n1. **Period**: ${from} → ${to}\n2. **Time entries by service**: Hours logged per service/budget line with team member breakdown\n3. **Billable totals**: If rates are available, calculate amounts per service\n4. **Budget consumed**: Planned vs actual hours per service\n5. **Invoice line items**: Suggested line items ready to copy into an invoice\n6. **Notes**: Any unbilled items, write-offs, or adjustments to flag`,\n },\n },\n ],\n };\n}\n\n/**\n * Get messages for a named prompt template\n */\nexport function getPromptMessages(name: string, args?: Record<string, string>): PromptResult {\n switch (name) {\n case 'end-of-day':\n return endOfDay(args);\n case 'project-review':\n return projectReview(args);\n case 'plan-sprint':\n return planSprint(args);\n case 'weekly-report':\n return weeklyReport(args);\n case 'invoice-prep':\n return invoicePrep(args);\n default:\n throw new Error(`Unknown prompt: ${name}`);\n }\n}\n","/**\n * Stdio transport handlers for Productive MCP Server\n *\n * This module contains the handler logic for the stdio transport.\n * The actual server startup is in index.ts.\n */\n\nimport type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';\n\nimport { getConfig, setConfig } from '@studiometa/productive-api';\n\nimport { executeToolWithCredentials } from './handlers.js';\nimport { PROMPT_DEFINITIONS, getPromptMessages } from './prompts/index.js';\nimport { TOOLS, STDIO_ONLY_TOOLS } from './tools.js';\n\nexport type ToolResult = CallToolResult;\n\n/**\n * Get all available tools (including stdio-only configuration tools)\n */\nexport function getAvailableTools() {\n return [...TOOLS, ...STDIO_ONLY_TOOLS];\n}\n\n/**\n * Get available prompts\n */\nexport function getAvailablePrompts() {\n return [\n {\n name: 'setup_productive',\n description: 'Interactive setup for Productive.io credentials',\n arguments: [],\n },\n ...PROMPT_DEFINITIONS,\n ];\n}\n\n/**\n * Handle the setup_productive prompt\n */\nexport async function handleSetupPrompt(): Promise<{\n messages: Array<{ role: string; content: { type: string; text: string } }>;\n}> {\n const config = await getConfig();\n const hasConfig = !!(config.organizationId && config.apiToken);\n\n return {\n messages: [\n {\n role: 'user',\n content: {\n type: 'text',\n text: hasConfig\n ? 'I have already configured Productive.io credentials. Would you like to update them?'\n : 'I need to configure my Productive.io credentials. Please help me set up:\\n1. Organization ID\\n2. API Token\\n3. User ID (optional)',\n },\n },\n ],\n };\n}\n\n/**\n * Handle the productive_configure tool\n */\nexport async function handleConfigureTool(args: {\n organizationId: string;\n apiToken: string;\n userId?: string;\n}): Promise<ToolResult> {\n const { organizationId, apiToken, userId } = args;\n\n await setConfig('organizationId', organizationId);\n await setConfig('apiToken', apiToken);\n if (userId) {\n await setConfig('userId', userId);\n }\n\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify(\n {\n success: true,\n message: 'Productive.io credentials configured successfully',\n configured: {\n organizationId,\n userId: userId || 'not set',\n apiToken: '***' + apiToken.slice(-4),\n },\n },\n null,\n 2,\n ),\n },\n ],\n };\n}\n\n/**\n * Handle the productive_get_config tool\n */\nexport async function handleGetConfigTool(): Promise<ToolResult> {\n const currentConfig = await getConfig();\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify(\n {\n organizationId: currentConfig.organizationId || 'not configured',\n userId: currentConfig.userId || 'not configured',\n apiToken: currentConfig.apiToken\n ? '***' + currentConfig.apiToken.slice(-4)\n : 'not configured',\n configured: !!(currentConfig.organizationId && currentConfig.apiToken),\n },\n null,\n 2,\n ),\n },\n ],\n };\n}\n\n/**\n * Handle a tool call request\n */\nexport async function handleToolCall(\n name: string,\n args: Record<string, unknown>,\n): Promise<ToolResult> {\n // Handle stdio-only configuration tools\n if (name === 'productive_configure') {\n return handleConfigureTool(args as Parameters<typeof handleConfigureTool>[0]);\n }\n\n if (name === 'productive_get_config') {\n return handleGetConfigTool();\n }\n\n // Get config for API tools\n const config = await getConfig();\n if (!config.organizationId || !config.apiToken) {\n return {\n content: [\n {\n type: 'text',\n text: 'Error: Productive.io credentials not configured. Please use the \"productive_configure\" tool to set your credentials, or set PRODUCTIVE_ORG_ID and PRODUCTIVE_API_TOKEN environment variables.',\n },\n ],\n isError: true,\n };\n }\n\n // Execute tool with credentials from config\n return executeToolWithCredentials(name, args, {\n organizationId: config.organizationId,\n apiToken: config.apiToken,\n userId: config.userId,\n });\n}\n\n/**\n * Handle a prompt request\n */\nexport async function handlePrompt(\n name: string,\n args?: Record<string, string>,\n): Promise<{\n messages: Array<{ role: string; content: { type: string; text: string } }>;\n}> {\n if (name === 'setup_productive') {\n return handleSetupPrompt();\n }\n\n return getPromptMessages(name, args);\n}\n"],"mappings":"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"}
|
package/dist/stdio.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as handlePrompt, i as handleGetConfigTool, n as getAvailableTools, o as handleSetupPrompt, r as handleConfigureTool, s as handleToolCall, t as getAvailablePrompts } from "./stdio-
|
|
1
|
+
import { a as handlePrompt, i as handleGetConfigTool, n as getAvailableTools, o as handleSetupPrompt, r as handleConfigureTool, s as handleToolCall, t as getAvailablePrompts } from "./stdio-jqfOnE6-.js";
|
|
2
2
|
export { getAvailablePrompts, getAvailableTools, handleConfigureTool, handleGetConfigTool, handlePrompt, handleSetupPrompt, handleToolCall };
|
package/dist/tools.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,oCAAoC,CAAC;AAwB/D;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,KAAK,EAAE,IAAI,EA+
|
|
1
|
+
{"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,oCAAoC,CAAC;AAwB/D;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,KAAK,EAAE,IAAI,EA+PvB,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,gBAAgB,EAAE,IAAI,EAoClC,CAAC"}
|