@mulmoclaude/chart-plugin 0.1.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.
Files changed (48) hide show
  1. package/dist/core/definition.d.ts +5 -0
  2. package/dist/core/definition.d.ts.map +1 -0
  3. package/dist/core/index.d.ts +5 -0
  4. package/dist/core/index.d.ts.map +1 -0
  5. package/dist/core/paths.d.ts +11 -0
  6. package/dist/core/paths.d.ts.map +1 -0
  7. package/dist/core/plugin.d.ts +23 -0
  8. package/dist/core/plugin.d.ts.map +1 -0
  9. package/dist/core/types.d.ts +22 -0
  10. package/dist/core/types.d.ts.map +1 -0
  11. package/dist/core.cjs +1 -0
  12. package/dist/core.js +2 -0
  13. package/dist/index.cjs +1 -0
  14. package/dist/index.d.ts +2 -0
  15. package/dist/index.d.ts.map +1 -0
  16. package/dist/index.js +3 -0
  17. package/dist/lang/de.d.ts +4 -0
  18. package/dist/lang/de.d.ts.map +1 -0
  19. package/dist/lang/en.d.ts +4 -0
  20. package/dist/lang/en.d.ts.map +1 -0
  21. package/dist/lang/es.d.ts +4 -0
  22. package/dist/lang/es.d.ts.map +1 -0
  23. package/dist/lang/fr.d.ts +4 -0
  24. package/dist/lang/fr.d.ts.map +1 -0
  25. package/dist/lang/index.d.ts +4 -0
  26. package/dist/lang/index.d.ts.map +1 -0
  27. package/dist/lang/ja.d.ts +4 -0
  28. package/dist/lang/ja.d.ts.map +1 -0
  29. package/dist/lang/ko.d.ts +4 -0
  30. package/dist/lang/ko.d.ts.map +1 -0
  31. package/dist/lang/messages.d.ts +7 -0
  32. package/dist/lang/messages.d.ts.map +1 -0
  33. package/dist/lang/ptBR.d.ts +4 -0
  34. package/dist/lang/ptBR.d.ts.map +1 -0
  35. package/dist/lang/zh.d.ts +4 -0
  36. package/dist/lang/zh.d.ts.map +1 -0
  37. package/dist/plugin-BrWEBWRb.cjs +1 -0
  38. package/dist/plugin-DIFaou52.js +106 -0
  39. package/dist/style.css +3 -0
  40. package/dist/vue/Preview.vue.d.ts +9 -0
  41. package/dist/vue/Preview.vue.d.ts.map +1 -0
  42. package/dist/vue/View.vue.d.ts +9 -0
  43. package/dist/vue/View.vue.d.ts.map +1 -0
  44. package/dist/vue/index.d.ts +14 -0
  45. package/dist/vue/index.d.ts.map +1 -0
  46. package/dist/vue.cjs +1 -0
  47. package/dist/vue.js +178 -0
  48. package/package.json +62 -0
@@ -0,0 +1,5 @@
1
+ import type { ToolDefinition } from "gui-chat-protocol";
2
+ export declare const TOOL_NAME = "presentChart";
3
+ export declare const TOOL_DEFINITION: ToolDefinition;
4
+ export default TOOL_DEFINITION;
5
+ //# sourceMappingURL=definition.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"definition.d.ts","sourceRoot":"","sources":["../../src/core/definition.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAExD,eAAO,MAAM,SAAS,iBAAiB,CAAC;AAExC,eAAO,MAAM,eAAe,EAAE,cAmD7B,CAAC;AAEF,eAAe,eAAe,CAAC"}
@@ -0,0 +1,5 @@
1
+ export type { ChartEntry, ChartDocument, ChartArgs, PresentChartData } from "./types";
2
+ export { TOOL_NAME, TOOL_DEFINITION } from "./definition";
3
+ export { pluginCore, executeChart, isValidChartDocument, type ChartExecuteContext } from "./plugin";
4
+ export { chartArtifactPath, slugify, type ChartPath } from "./paths";
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,UAAU,EAAE,aAAa,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AACtF,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC1D,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,oBAAoB,EAAE,KAAK,mBAAmB,EAAE,MAAM,UAAU,CAAC;AACpG,OAAO,EAAE,iBAAiB,EAAE,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,SAAS,CAAC"}
@@ -0,0 +1,11 @@
1
+ /** Lowercase ASCII slug; empty / non-ASCII input falls back to `fallback`. */
2
+ export declare function slugify(title: string | undefined, fallback?: string): string;
3
+ export interface ChartPath {
4
+ /** Path relative to the artifacts root — what `files.artifacts.write` takes. */
5
+ relPath: string;
6
+ /** Workspace-relative path — surfaced to the host/LLM for display. */
7
+ filePath: string;
8
+ }
9
+ /** Build the `charts/<YYYY>/<MM>/<slug>-<ts>.chart.json` location for a document. */
10
+ export declare function chartArtifactPath(title: string | undefined, now?: Date): ChartPath;
11
+ //# sourceMappingURL=paths.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../../src/core/paths.ts"],"names":[],"mappings":"AASA,8EAA8E;AAC9E,wBAAgB,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,EAAE,QAAQ,SAAU,GAAG,MAAM,CAO7E;AASD,MAAM,WAAW,SAAS;IACxB,gFAAgF;IAChF,OAAO,EAAE,MAAM,CAAC;IAChB,sEAAsE;IACtE,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,qFAAqF;AACrF,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,EAAE,GAAG,GAAE,IAAiB,GAAG,SAAS,CAI9F"}
@@ -0,0 +1,23 @@
1
+ import type { FileOps, ToolPluginCore, ToolResult } from "gui-chat-protocol";
2
+ import { TOOL_NAME, TOOL_DEFINITION } from "./definition";
3
+ import type { ChartArgs, ChartDocument, PresentChartData } from "./types";
4
+ /** Host capabilities `executeChart` needs, delivered through the GENERIC
5
+ * gui-chat-protocol runtime — only `files.artifacts` (the shared,
6
+ * user-browsable output area). No chart-specific host method: all chart
7
+ * logic lives in this package. */
8
+ export interface ChartExecuteContext {
9
+ files: {
10
+ artifacts: FileOps;
11
+ };
12
+ }
13
+ export declare function isValidChartDocument(value: unknown): value is ChartDocument;
14
+ /**
15
+ * Validate the chart document and persist it to the shared artifacts area
16
+ * (`artifacts/charts/<YYYY>/<MM>/<slug>-<ts>.chart.json`) via the generic
17
+ * `files.artifacts` runtime capability. Returns a ToolResult whose `data`
18
+ * drives the View and preview sidebar.
19
+ */
20
+ export declare const executeChart: (context: ChartExecuteContext, args: ChartArgs) => Promise<ToolResult<PresentChartData>>;
21
+ export declare const pluginCore: ToolPluginCore<PresentChartData, PresentChartData, ChartArgs>;
22
+ export { TOOL_NAME, TOOL_DEFINITION };
23
+ //# sourceMappingURL=plugin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../src/core/plugin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC7E,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAE1D,OAAO,KAAK,EAAE,SAAS,EAAE,aAAa,EAAc,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAEtF;;;mCAGmC;AACnC,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE;QAAE,SAAS,EAAE,OAAO,CAAA;KAAE,CAAC;CAC/B;AAiBD,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,aAAa,CAM3E;AAED;;;;;GAKG;AACH,eAAO,MAAM,YAAY,GAAU,SAAS,mBAAmB,EAAE,MAAM,SAAS,KAAG,OAAO,CAAC,UAAU,CAAC,gBAAgB,CAAC,CAyBtH,CAAC;AAEF,eAAO,MAAM,UAAU,EAAE,cAAc,CAAC,gBAAgB,EAAE,gBAAgB,EAAE,SAAS,CAQpF,CAAC;AAEF,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,CAAC"}
@@ -0,0 +1,22 @@
1
+ export interface ChartEntry {
2
+ title?: string;
3
+ type?: string;
4
+ option: Record<string, unknown>;
5
+ }
6
+ export interface ChartDocument {
7
+ title?: string;
8
+ charts: ChartEntry[];
9
+ }
10
+ /** Tool-call args for presentChart. */
11
+ export interface ChartArgs {
12
+ document: ChartDocument;
13
+ title?: string;
14
+ }
15
+ /** `data` payload returned to the host: drives the View and the
16
+ * preview sidebar, and records where the document was persisted. */
17
+ export interface PresentChartData {
18
+ document: ChartDocument;
19
+ title?: string;
20
+ filePath: string;
21
+ }
22
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,UAAU;IACzB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACjC;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,UAAU,EAAE,CAAC;CACtB;AAED,uCAAuC;AACvC,MAAM,WAAW,SAAS;IACxB,QAAQ,EAAE,aAAa,CAAC;IACxB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;qEACqE;AACrE,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,aAAa,CAAC;IACxB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;CAClB"}
package/dist/core.cjs ADDED
@@ -0,0 +1 @@
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./plugin-BrWEBWRb.cjs");exports.TOOL_DEFINITION=e.o,exports.TOOL_NAME=e.s,exports.chartArtifactPath=e.i,exports.executeChart=e.t,exports.isValidChartDocument=e.n,exports.pluginCore=e.r,exports.slugify=e.a;
package/dist/core.js ADDED
@@ -0,0 +1,2 @@
1
+ import { a as e, i as t, n, o as r, r as i, s as a, t as o } from "./plugin-DIFaou52.js";
2
+ export { r as TOOL_DEFINITION, a as TOOL_NAME, t as chartArtifactPath, o as executeChart, n as isValidChartDocument, i as pluginCore, e as slugify };
package/dist/index.cjs ADDED
@@ -0,0 +1 @@
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./plugin-BrWEBWRb.cjs");require("./core.cjs"),exports.TOOL_DEFINITION=e.o,exports.TOOL_NAME=e.s,exports.chartArtifactPath=e.i,exports.executeChart=e.t,exports.isValidChartDocument=e.n,exports.pluginCore=e.r,exports.slugify=e.a;
@@ -0,0 +1,2 @@
1
+ export * from "./core/index";
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,3 @@
1
+ import { a as e, i as t, n, o as r, r as i, s as a, t as o } from "./plugin-DIFaou52.js";
2
+ import "./core.js";
3
+ export { r as TOOL_DEFINITION, a as TOOL_NAME, t as chartArtifactPath, o as executeChart, n as isValidChartDocument, i as pluginCore, e as slugify };
@@ -0,0 +1,4 @@
1
+ import type { Messages } from "./messages";
2
+ declare const de: Messages;
3
+ export default de;
4
+ //# sourceMappingURL=de.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"de.d.ts","sourceRoot":"","sources":["../../src/lang/de.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C,QAAA,MAAM,EAAE,EAAE,QAKT,CAAC;AAEF,eAAe,EAAE,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { Messages } from "./messages";
2
+ declare const en: Messages;
3
+ export default en;
4
+ //# sourceMappingURL=en.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"en.d.ts","sourceRoot":"","sources":["../../src/lang/en.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C,QAAA,MAAM,EAAE,EAAE,QAKT,CAAC;AAEF,eAAe,EAAE,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { Messages } from "./messages";
2
+ declare const es: Messages;
3
+ export default es;
4
+ //# sourceMappingURL=es.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"es.d.ts","sourceRoot":"","sources":["../../src/lang/es.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C,QAAA,MAAM,EAAE,EAAE,QAKT,CAAC;AAEF,eAAe,EAAE,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { Messages } from "./messages";
2
+ declare const fr: Messages;
3
+ export default fr;
4
+ //# sourceMappingURL=fr.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fr.d.ts","sourceRoot":"","sources":["../../src/lang/fr.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C,QAAA,MAAM,EAAE,EAAE,QAKT,CAAC;AAEF,eAAe,EAAE,CAAC"}
@@ -0,0 +1,4 @@
1
+ import { type ComputedRef } from "vue";
2
+ import type { Messages } from "./messages";
3
+ export declare function useT(): ComputedRef<Messages>;
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/lang/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAyB,KAAK,WAAW,EAAY,MAAM,KAAK,CAAC;AAExE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAsB3C,wBAAgB,IAAI,IAAI,WAAW,CAAC,QAAQ,CAAC,CAI5C"}
@@ -0,0 +1,4 @@
1
+ import type { Messages } from "./messages";
2
+ declare const ja: Messages;
3
+ export default ja;
4
+ //# sourceMappingURL=ja.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ja.d.ts","sourceRoot":"","sources":["../../src/lang/ja.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C,QAAA,MAAM,EAAE,EAAE,QAKT,CAAC;AAEF,eAAe,EAAE,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { Messages } from "./messages";
2
+ declare const ko: Messages;
3
+ export default ko;
4
+ //# sourceMappingURL=ko.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ko.d.ts","sourceRoot":"","sources":["../../src/lang/ko.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C,QAAA,MAAM,EAAE,EAAE,QAKT,CAAC;AAEF,eAAe,EAAE,CAAC"}
@@ -0,0 +1,7 @@
1
+ export interface Messages {
2
+ untitled: string;
3
+ chartCount(count: number): string;
4
+ chartTitle(num: number): string;
5
+ png: string;
6
+ }
7
+ //# sourceMappingURL=messages.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../../src/lang/messages.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,QAAQ;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC;IAClC,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC;IAChC,GAAG,EAAE,MAAM,CAAC;CACb"}
@@ -0,0 +1,4 @@
1
+ import type { Messages } from "./messages";
2
+ declare const ptBR: Messages;
3
+ export default ptBR;
4
+ //# sourceMappingURL=ptBR.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ptBR.d.ts","sourceRoot":"","sources":["../../src/lang/ptBR.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C,QAAA,MAAM,IAAI,EAAE,QAKX,CAAC;AAEF,eAAe,IAAI,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { Messages } from "./messages";
2
+ declare const zh: Messages;
3
+ export default zh;
4
+ //# sourceMappingURL=zh.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"zh.d.ts","sourceRoot":"","sources":["../../src/lang/zh.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C,QAAA,MAAM,EAAE,EAAE,QAKT,CAAC;AAEF,eAAe,EAAE,CAAC"}
@@ -0,0 +1 @@
1
+ var e=`presentChart`,t={type:`function`,name:e,description:"Save and present one or more Apache ECharts visualizations as a single document. Use this for line, bar, area, scatter, pie, candlestick, heatmap, sankey, or graph/network charts — anything ECharts supports. Pass ECharts option object(s) directly; the plugin calls setOption on each one. Use `charts: []` array form even for a single chart so multi-chart dashboards share the same slug.",parameters:{type:`object`,properties:{document:{type:`object`,description:`Chart document. Contains an optional title and an array of chart entries. Each entry has its own ECharts option object that the UI renders independently.`,properties:{title:{type:`string`,description:`Optional human-friendly title for the whole document. Used to derive the file slug and as the preview label.`},charts:{type:`array`,description:`List of charts to render, in order. Each charts[i].option is passed as-is to ECharts' setOption().`,items:{type:`object`,properties:{title:{type:`string`,description:`Optional short label for this specific chart (shown above it in the UI).`},type:{type:`string`,description:`Informational tag shown in the UI (e.g. 'line', 'bar', 'candlestick', 'sankey'). The actual chart type is determined by option.series[].type.`},option:{type:`object`,description:`Full ECharts option object. Include all series, axes, tooltip, legend, dataset — anything ECharts accepts. Keep data inline; large datasets are fine.`}},required:[`option`]}}},required:[`charts`]},title:{type:`string`,description:`Short label shown in the canvas preview sidebar. Defaults to document.title, or 'Chart' when both are blank.`}},required:[`document`]}},n=`charts`,r=`artifacts`;function i(e,t=`chart`){return e&&e.toLowerCase().replace(/[^a-z0-9]+/g,`-`).replace(/^-+|-+$/g,``)||t}function a(e){return`${e.getUTCFullYear()}/${String(e.getUTCMonth()+1).padStart(2,`0`)}`}function o(e,t=new Date){let o=`${i(e)}-${t.getTime()}.chart.json`,s=`${n}/${a(t)}/${o}`;return{relPath:s,filePath:`${r}/${s}`}}function s(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function c(e){return e===void 0||typeof e==`string`}function l(e){return!s(e)||!c(e.title)||!c(e.type)?!1:s(e.option)}function u(e){return!s(e)||!c(e.title)||!Array.isArray(e.charts)||e.charts.length===0?!1:e.charts.every(e=>l(e))}var d=async(e,t)=>{let{document:n,title:r}=t;if(!u(n))return{message:`document must be { charts: [{ option: {...}, title?, type? }, ...] } with at least one entry`,instructions:`Acknowledge that the chart could not be created and retry with a valid ECharts document shape.`};if(r!==void 0&&typeof r!=`string`)return{message:`title must be a string when provided`,instructions:`Acknowledge the error and retry with a string title (or omit it).`};let{relPath:i,filePath:a}=o(r??n.title??`chart`);await e.files.artifacts.write(i,`${JSON.stringify(n,null,2)}\n`);let s=n.charts.length;return{message:`Saved chart document to ${a}`,data:{document:n,title:r,filePath:a},instructions:`Acknowledge that the chart(s) have been presented to the user. The document contains ${s} chart${s===1?``:`s`}.`}},f={toolDefinition:t,execute:d,generatingMessage:`Rendering chart…`,isEnabled:()=>!0};Object.defineProperty(exports,"a",{enumerable:!0,get:function(){return i}}),Object.defineProperty(exports,"i",{enumerable:!0,get:function(){return o}}),Object.defineProperty(exports,"n",{enumerable:!0,get:function(){return u}}),Object.defineProperty(exports,"o",{enumerable:!0,get:function(){return t}}),Object.defineProperty(exports,"r",{enumerable:!0,get:function(){return f}}),Object.defineProperty(exports,"s",{enumerable:!0,get:function(){return e}}),Object.defineProperty(exports,"t",{enumerable:!0,get:function(){return d}});
@@ -0,0 +1,106 @@
1
+ //#region src/core/definition.ts
2
+ var e = "presentChart", t = {
3
+ type: "function",
4
+ name: e,
5
+ description: "Save and present one or more Apache ECharts visualizations as a single document. Use this for line, bar, area, scatter, pie, candlestick, heatmap, sankey, or graph/network charts — anything ECharts supports. Pass ECharts option object(s) directly; the plugin calls setOption on each one. Use `charts: []` array form even for a single chart so multi-chart dashboards share the same slug.",
6
+ parameters: {
7
+ type: "object",
8
+ properties: {
9
+ document: {
10
+ type: "object",
11
+ description: "Chart document. Contains an optional title and an array of chart entries. Each entry has its own ECharts option object that the UI renders independently.",
12
+ properties: {
13
+ title: {
14
+ type: "string",
15
+ description: "Optional human-friendly title for the whole document. Used to derive the file slug and as the preview label."
16
+ },
17
+ charts: {
18
+ type: "array",
19
+ description: "List of charts to render, in order. Each charts[i].option is passed as-is to ECharts' setOption().",
20
+ items: {
21
+ type: "object",
22
+ properties: {
23
+ title: {
24
+ type: "string",
25
+ description: "Optional short label for this specific chart (shown above it in the UI)."
26
+ },
27
+ type: {
28
+ type: "string",
29
+ description: "Informational tag shown in the UI (e.g. 'line', 'bar', 'candlestick', 'sankey'). The actual chart type is determined by option.series[].type."
30
+ },
31
+ option: {
32
+ type: "object",
33
+ description: "Full ECharts option object. Include all series, axes, tooltip, legend, dataset — anything ECharts accepts. Keep data inline; large datasets are fine."
34
+ }
35
+ },
36
+ required: ["option"]
37
+ }
38
+ }
39
+ },
40
+ required: ["charts"]
41
+ },
42
+ title: {
43
+ type: "string",
44
+ description: "Short label shown in the canvas preview sidebar. Defaults to document.title, or 'Chart' when both are blank."
45
+ }
46
+ },
47
+ required: ["document"]
48
+ }
49
+ }, n = "charts", r = "artifacts";
50
+ function i(e, t = "chart") {
51
+ return e && e.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || t;
52
+ }
53
+ function a(e) {
54
+ return `${e.getUTCFullYear()}/${String(e.getUTCMonth() + 1).padStart(2, "0")}`;
55
+ }
56
+ function o(e, t = /* @__PURE__ */ new Date()) {
57
+ let o = `${i(e)}-${t.getTime()}.chart.json`, s = `${n}/${a(t)}/${o}`;
58
+ return {
59
+ relPath: s,
60
+ filePath: `${r}/${s}`
61
+ };
62
+ }
63
+ //#endregion
64
+ //#region src/core/plugin.ts
65
+ function s(e) {
66
+ return typeof e == "object" && !!e && !Array.isArray(e);
67
+ }
68
+ function c(e) {
69
+ return e === void 0 || typeof e == "string";
70
+ }
71
+ function l(e) {
72
+ return !s(e) || !c(e.title) || !c(e.type) ? !1 : s(e.option);
73
+ }
74
+ function u(e) {
75
+ return !s(e) || !c(e.title) || !Array.isArray(e.charts) || e.charts.length === 0 ? !1 : e.charts.every((e) => l(e));
76
+ }
77
+ var d = async (e, t) => {
78
+ let { document: n, title: r } = t;
79
+ if (!u(n)) return {
80
+ message: "document must be { charts: [{ option: {...}, title?, type? }, ...] } with at least one entry",
81
+ instructions: "Acknowledge that the chart could not be created and retry with a valid ECharts document shape."
82
+ };
83
+ if (r !== void 0 && typeof r != "string") return {
84
+ message: "title must be a string when provided",
85
+ instructions: "Acknowledge the error and retry with a string title (or omit it)."
86
+ };
87
+ let { relPath: i, filePath: a } = o(r ?? n.title ?? "chart");
88
+ await e.files.artifacts.write(i, `${JSON.stringify(n, null, 2)}\n`);
89
+ let s = n.charts.length;
90
+ return {
91
+ message: `Saved chart document to ${a}`,
92
+ data: {
93
+ document: n,
94
+ title: r,
95
+ filePath: a
96
+ },
97
+ instructions: `Acknowledge that the chart(s) have been presented to the user. The document contains ${s} chart${s === 1 ? "" : "s"}.`
98
+ };
99
+ }, f = {
100
+ toolDefinition: t,
101
+ execute: d,
102
+ generatingMessage: "Rendering chart…",
103
+ isEnabled: () => !0
104
+ };
105
+ //#endregion
106
+ export { i as a, o as i, u as n, t as o, f as r, e as s, d as t };
package/dist/style.css ADDED
@@ -0,0 +1,3 @@
1
+ /*! tailwindcss v4.3.1 | MIT License | https://tailwindcss.com */
2
+ @layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-space-y-reverse:0;--tw-border-style:solid;--tw-leading:initial;--tw-font-weight:initial;--tw-tracking:initial}}}@layer theme{:root,:host{--font-sans:ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--color-blue-50:oklch(97% .014 254.604);--color-blue-700:oklch(48.8% .243 264.376);--color-gray-50:oklch(98.5% .002 247.839);--color-gray-100:oklch(96.7% .003 264.542);--color-gray-200:oklch(92.8% .006 264.531);--color-gray-300:oklch(87.2% .01 258.338);--color-gray-500:oklch(55.1% .027 264.364);--color-gray-700:oklch(37.3% .034 259.733);--color-gray-800:oklch(27.8% .033 256.848);--color-white:#fff;--spacing:.25rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--font-weight-medium:500;--tracking-wide:.025em;--leading-relaxed:1.625;--radius-lg:.5rem;--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab, currentcolor 50%, transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.relative{position:relative}.mb-1{margin-bottom:var(--spacing)}.flex{display:flex}.table{display:table}.h-\[400px\]{height:400px}.h-full{height:100%}.w-full{width:100%}.min-w-0{min-width:0}.flex-1{flex:1}.shrink-0{flex-shrink:0}.resize{resize:both}.flex-col{flex-direction:column}.items-center{align-items:center}.justify-between{justify-content:space-between}.gap-2{gap:calc(var(--spacing) * 2)}:where(.space-y-4>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 4) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 4) * calc(1 - var(--tw-space-y-reverse)))}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.overflow-hidden{overflow:hidden}.overflow-y-auto{overflow-y:auto}.rounded{border-radius:.25rem}.rounded-lg{border-radius:var(--radius-lg)}.border{border-style:var(--tw-border-style);border-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-gray-100{border-color:var(--color-gray-100)}.border-gray-200{border-color:var(--color-gray-200)}.border-gray-300{border-color:var(--color-gray-300)}.bg-blue-50{background-color:var(--color-blue-50)}.bg-white{background-color:var(--color-white)}.p-2{padding:calc(var(--spacing) * 2)}.p-4{padding:calc(var(--spacing) * 4)}.px-1\.5{padding-inline:calc(var(--spacing) * 1.5)}.px-2{padding-inline:calc(var(--spacing) * 2)}.px-3{padding-inline:calc(var(--spacing) * 3)}.px-4{padding-inline:calc(var(--spacing) * 4)}.py-0\.5{padding-block:calc(var(--spacing) * .5)}.py-1{padding-block:var(--spacing)}.py-2{padding-block:calc(var(--spacing) * 2)}.align-middle{vertical-align:middle}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.text-\[10px\]{font-size:10px}.leading-relaxed{--tw-leading:var(--leading-relaxed);line-height:var(--leading-relaxed)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.tracking-wide{--tw-tracking:var(--tracking-wide);letter-spacing:var(--tracking-wide)}.text-blue-700{color:var(--color-blue-700)}.text-gray-500{color:var(--color-gray-500)}.text-gray-700{color:var(--color-gray-700)}.text-gray-800{color:var(--color-gray-800)}.uppercase{text-transform:uppercase}@media (hover:hover){.hover\:bg-gray-50:hover{background-color:var(--color-gray-50)}}}@property --tw-space-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}
3
+ /*$vite$:1*/
@@ -0,0 +1,9 @@
1
+ import type { ToolResultComplete } from "gui-chat-protocol/vue";
2
+ import type { PresentChartData } from "../core/types";
3
+ type __VLS_Props = {
4
+ result: ToolResultComplete<PresentChartData>;
5
+ };
6
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
7
+ declare const _default: typeof __VLS_export;
8
+ export default _default;
9
+ //# sourceMappingURL=Preview.vue.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Preview.vue.d.ts","sourceRoot":"","sources":["../../src/vue/Preview.vue"],"names":[],"mappings":"AAqDA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAEtD,KAAK,WAAW,GAAG;IAAE,MAAM,EAAE,kBAAkB,CAAC,gBAAgB,CAAC,CAAA;CAAE,CAAC;AA+EpE,QAAA,MAAM,YAAY,kSAEhB,CAAC;wBACkB,OAAO,YAAY;AAAxC,wBAAyC"}
@@ -0,0 +1,9 @@
1
+ import type { ToolResultComplete } from "gui-chat-protocol/vue";
2
+ import type { PresentChartData } from "../core/types";
3
+ type __VLS_Props = {
4
+ selectedResult: ToolResultComplete<PresentChartData>;
5
+ };
6
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
7
+ declare const _default: typeof __VLS_export;
8
+ export default _default;
9
+ //# sourceMappingURL=View.vue.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"View.vue.d.ts","sourceRoot":"","sources":["../../src/vue/View.vue"],"names":[],"mappings":"AA6JA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,KAAK,EAAc,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAKlE,KAAK,WAAW,GAAG;IACjB,cAAc,EAAE,kBAAkB,CAAC,gBAAgB,CAAC,CAAC;CACtD,CAAC;AAiQF,QAAA,MAAM,YAAY,kSAEhB,CAAC;wBACkB,OAAO,YAAY;AAAxC,wBAAyC"}
@@ -0,0 +1,14 @@
1
+ import "../style.css";
2
+ import type { ToolPlugin } from "gui-chat-protocol/vue";
3
+ import type { ChartArgs, PresentChartData } from "../core/types";
4
+ import View from "./View.vue";
5
+ import Preview from "./Preview.vue";
6
+ export declare const plugin: ToolPlugin<PresentChartData, PresentChartData, ChartArgs>;
7
+ export type { ChartArgs, ChartDocument, ChartEntry, PresentChartData } from "../core/types";
8
+ export { TOOL_NAME, TOOL_DEFINITION, executeChart, isValidChartDocument, pluginCore, type ChartExecuteContext } from "../core/plugin";
9
+ export { View, Preview };
10
+ declare const _default: {
11
+ plugin: ToolPlugin<PresentChartData, PresentChartData, ChartArgs, import("gui-chat-protocol/vue").InputHandler, Record<string, unknown>>;
12
+ };
13
+ export default _default;
14
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/vue/index.ts"],"names":[],"mappings":"AAAA,OAAO,cAAc,CAAC;AAEtB,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,KAAK,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAEjE,OAAO,IAAI,MAAM,YAAY,CAAC;AAC9B,OAAO,OAAO,MAAM,eAAe,CAAC;AAEpC,eAAO,MAAM,MAAM,EAAE,UAAU,CAAC,gBAAgB,EAAE,gBAAgB,EAAE,SAAS,CAI5E,CAAC;AAEF,YAAY,EAAE,SAAS,EAAE,aAAa,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAC5F,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,YAAY,EAAE,oBAAoB,EAAE,UAAU,EAAE,KAAK,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AACtI,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;;;;AAEzB,wBAA0B"}
package/dist/vue.cjs ADDED
@@ -0,0 +1 @@
1
+ Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:`Module`}});var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},s=(n,r,a)=>(a=n==null?{}:e(i(n)),o(r||!n||!n.__esModule?t(a,`default`,{value:n,enumerable:!0}):a,n));const c=require("./plugin-BrWEBWRb.cjs");let l=require("vue"),u=require("echarts");u=s(u,1);let d=require("gui-chat-protocol/vue");var f={de:{untitled:`Diagramm`,chartCount:e=>`${e} Diagramm${e===1?``:`e`}`,chartTitle:e=>`Diagramm ${e}`,png:`PNG`},en:{untitled:`Chart`,chartCount:e=>`${e} chart${e===1?``:`s`}`,chartTitle:e=>`Chart ${e}`,png:`PNG`},es:{untitled:`Gráfico`,chartCount:e=>`${e} gráfico${e===1?``:`s`}`,chartTitle:e=>`Gráfico ${e}`,png:`PNG`},fr:{untitled:`Graphique`,chartCount:e=>`${e} graphique${e===1?``:`s`}`,chartTitle:e=>`Graphique ${e}`,png:`PNG`},ja:{untitled:`チャート`,chartCount:e=>`${e} チャート`,chartTitle:e=>`チャート ${e}`,png:`PNG`},ko:{untitled:`차트`,chartCount:e=>`${e}개 차트`,chartTitle:e=>`차트 ${e}`,png:`PNG`},"pt-BR":{untitled:`Gráfico`,chartCount:e=>`${e} gráfico${e===1?``:`s`}`,chartTitle:e=>`Gráfico ${e}`,png:`PNG`},zh:{untitled:`图表`,chartCount:e=>`${e} 个图表`,chartTitle:e=>`图表 ${e}`,png:`PNG`}};function p(e){return Object.prototype.hasOwnProperty.call(f,e)}function m(){let e=(0,l.inject)(d.PLUGIN_RUNTIME_KEY,void 0)?.locale??(0,l.ref)(`en`);return(0,l.computed)(()=>p(e.value)?f[e.value]:f.en)}var h={class:`h-full flex flex-col overflow-hidden`},g={class:`px-4 py-2 border-b border-gray-100 shrink-0 flex items-center justify-between`},_={class:`text-sm font-medium text-gray-700 truncate`},v={class:`text-xs text-gray-500 shrink-0`},y={class:`flex-1 overflow-y-auto p-4 space-y-4`},b=[`data-testid`],x={class:`px-3 py-2 border-b border-gray-100 flex items-center justify-between gap-2`},S={class:`flex items-center gap-2 min-w-0`},C={class:`text-sm font-medium text-gray-800 truncate`},w={key:0,class:`text-[10px] uppercase tracking-wide rounded px-1.5 py-0.5 bg-blue-50 text-blue-700 shrink-0`},T=[`data-testid`,`onClick`],E=[`data-testid`],D=(0,l.defineComponent)({__name:`View`,props:{selectedResult:{}},setup(e){let t=m(),n=e,r=(0,l.computed)(()=>n.selectedResult.data),i=(0,l.computed)(()=>r.value?.document?.charts??[]),a=(0,l.computed)(()=>r.value?.title??r.value?.document?.title),o=(0,l.ref)([]),s=[];function c(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function d(e,t){o.value[e]=t}function f(){for(let e of s)e.dispose();s.length=0}function p(e){let{dataZoom:t}=e;if(t==null)return e;let n=e=>c(e)?{...e,zoomOnMouseWheel:!1,moveOnMouseWheel:!1}:e,r=Array.isArray(t)?t.map(n):n(t);return{...e,dataZoom:r}}function D(){f();for(let e=0;e<i.value.length;e+=1){let t=o.value[e],n=i.value[e];if(!t||!n)continue;let r=u.init(t);try{r.setOption(p(n.option))}catch{}s[e]=r}}function O(){for(let e of s)e.resize()}(0,l.onMounted)(()=>{queueMicrotask(D),window.addEventListener(`resize`,O)}),(0,l.onBeforeUnmount)(()=>{window.removeEventListener(`resize`,O),f()}),(0,l.watch)(()=>r.value?.filePath,()=>queueMicrotask(D));function k(e,t){let n=s[e];if(!n)return;let r=n.getDataURL({type:`png`,pixelRatio:2,backgroundColor:`#ffffff`}),i=(t??a.value??`chart`).toLowerCase().replace(/[^a-z0-9-]+/g,`-`);for(;i.startsWith(`-`);)i=i.slice(1);for(;i.endsWith(`-`);)i=i.slice(0,-1);i||=`chart`;let o=document.createElement(`a`);o.href=r,o.download=`${i}-${e+1}.png`,document.body.appendChild(o),o.click(),document.body.removeChild(o)}return(e,n)=>((0,l.openBlock)(),(0,l.createElementBlock)(`div`,h,[(0,l.createElementVNode)(`div`,g,[(0,l.createElementVNode)(`span`,_,(0,l.toDisplayString)(a.value??(0,l.unref)(t).untitled),1),(0,l.createElementVNode)(`span`,v,(0,l.toDisplayString)((0,l.unref)(t).chartCount(i.value.length)),1)]),(0,l.createElementVNode)(`div`,y,[((0,l.openBlock)(!0),(0,l.createElementBlock)(l.Fragment,null,(0,l.renderList)(i.value,(e,r)=>((0,l.openBlock)(),(0,l.createElementBlock)(`div`,{key:r,class:`border border-gray-200 rounded-lg bg-white`,"data-testid":`chart-card-${r}`},[(0,l.createElementVNode)(`div`,x,[(0,l.createElementVNode)(`div`,S,[(0,l.createElementVNode)(`span`,C,(0,l.toDisplayString)(e.title??(0,l.unref)(t).chartTitle(r+1)),1),e.type?((0,l.openBlock)(),(0,l.createElementBlock)(`span`,w,(0,l.toDisplayString)(e.type),1)):(0,l.createCommentVNode)(``,!0)]),(0,l.createElementVNode)(`button`,{class:`px-2 py-1 text-xs rounded border border-gray-300 text-gray-500 hover:bg-gray-50 shrink-0`,"data-testid":`chart-export-png-${r}`,onClick:t=>k(r,e.title)},[n[0]||=(0,l.createElementVNode)(`span`,{class:`material-icons text-sm align-middle`},`download`,-1),(0,l.createTextVNode)(` `+(0,l.toDisplayString)((0,l.unref)(t).png),1)],8,T)]),(0,l.createElementVNode)(`div`,{ref_for:!0,ref:e=>d(r,e),class:`w-full h-[400px]`,"data-testid":`chart-canvas-${r}`},null,8,E)],8,b))),128))])]))}}),O={class:`p-2 text-sm`},k={class:`font-medium text-gray-700 truncate mb-1`},A={key:0,class:`text-xs text-gray-500 leading-relaxed truncate`},j=(0,l.defineComponent)({__name:`Preview`,props:{result:{}},setup(e){let t=e,n=(0,l.computed)(()=>t.result.data),r=(0,l.computed)(()=>n.value?.title??n.value?.document?.title??`Chart`),i=(0,l.computed)(()=>{let e=n.value?.document?.charts??[];if(e.length===0)return``;let t=e.map(e=>e.type??a(e.option)).filter(e=>!!e).slice(0,3),r=e.length>t.length?`, …`:``,i=t.join(`, `),o=e.length===1?``:`s`,s=i?`: ${i}${r}`:``;return`${e.length} chart${o}${s}`});function a(e){let{series:t}=e;if(Array.isArray(t)&&t.length>0){let e=t[0];if(typeof e.type==`string`)return e.type}else if(t&&typeof t==`object`){let e=t.type;if(typeof e==`string`)return e}return null}return(e,t)=>((0,l.openBlock)(),(0,l.createElementBlock)(`div`,O,[(0,l.createElementVNode)(`div`,k,(0,l.toDisplayString)(r.value),1),i.value?((0,l.openBlock)(),(0,l.createElementBlock)(`div`,A,(0,l.toDisplayString)(i.value),1)):(0,l.createCommentVNode)(``,!0)]))}}),M={...c.r,viewComponent:D,previewComponent:j},N={plugin:M};exports.Preview=j,exports.TOOL_DEFINITION=c.o,exports.TOOL_NAME=c.s,exports.View=D,exports.default=N,exports.executeChart=c.t,exports.isValidChartDocument=c.n,exports.plugin=M,exports.pluginCore=c.r;
package/dist/vue.js ADDED
@@ -0,0 +1,178 @@
1
+ import { n as e, o as t, r as n, s as r, t as i } from "./plugin-DIFaou52.js";
2
+ import { Fragment as a, computed as o, createCommentVNode as s, createElementBlock as c, createElementVNode as l, createTextVNode as u, defineComponent as d, inject as f, onBeforeUnmount as p, onMounted as m, openBlock as h, ref as g, renderList as _, toDisplayString as v, unref as y, watch as b } from "vue";
3
+ import * as x from "echarts";
4
+ import { PLUGIN_RUNTIME_KEY as S } from "gui-chat-protocol/vue";
5
+ //#endregion
6
+ //#region src/lang/index.ts
7
+ var C = {
8
+ de: {
9
+ untitled: "Diagramm",
10
+ chartCount: (e) => `${e} Diagramm${e === 1 ? "" : "e"}`,
11
+ chartTitle: (e) => `Diagramm ${e}`,
12
+ png: "PNG"
13
+ },
14
+ en: {
15
+ untitled: "Chart",
16
+ chartCount: (e) => `${e} chart${e === 1 ? "" : "s"}`,
17
+ chartTitle: (e) => `Chart ${e}`,
18
+ png: "PNG"
19
+ },
20
+ es: {
21
+ untitled: "Gráfico",
22
+ chartCount: (e) => `${e} gráfico${e === 1 ? "" : "s"}`,
23
+ chartTitle: (e) => `Gráfico ${e}`,
24
+ png: "PNG"
25
+ },
26
+ fr: {
27
+ untitled: "Graphique",
28
+ chartCount: (e) => `${e} graphique${e === 1 ? "" : "s"}`,
29
+ chartTitle: (e) => `Graphique ${e}`,
30
+ png: "PNG"
31
+ },
32
+ ja: {
33
+ untitled: "チャート",
34
+ chartCount: (e) => `${e} チャート`,
35
+ chartTitle: (e) => `チャート ${e}`,
36
+ png: "PNG"
37
+ },
38
+ ko: {
39
+ untitled: "차트",
40
+ chartCount: (e) => `${e}개 차트`,
41
+ chartTitle: (e) => `차트 ${e}`,
42
+ png: "PNG"
43
+ },
44
+ "pt-BR": {
45
+ untitled: "Gráfico",
46
+ chartCount: (e) => `${e} gráfico${e === 1 ? "" : "s"}`,
47
+ chartTitle: (e) => `Gráfico ${e}`,
48
+ png: "PNG"
49
+ },
50
+ zh: {
51
+ untitled: "图表",
52
+ chartCount: (e) => `${e} 个图表`,
53
+ chartTitle: (e) => `图表 ${e}`,
54
+ png: "PNG"
55
+ }
56
+ };
57
+ function w(e) {
58
+ return Object.prototype.hasOwnProperty.call(C, e);
59
+ }
60
+ function T() {
61
+ let e = f(S, void 0)?.locale ?? g("en");
62
+ return o(() => w(e.value) ? C[e.value] : C.en);
63
+ }
64
+ //#endregion
65
+ //#region src/vue/View.vue?vue&type=script&setup=true&lang.ts
66
+ var E = { class: "h-full flex flex-col overflow-hidden" }, D = { class: "px-4 py-2 border-b border-gray-100 shrink-0 flex items-center justify-between" }, O = { class: "text-sm font-medium text-gray-700 truncate" }, k = { class: "text-xs text-gray-500 shrink-0" }, A = { class: "flex-1 overflow-y-auto p-4 space-y-4" }, j = ["data-testid"], M = { class: "px-3 py-2 border-b border-gray-100 flex items-center justify-between gap-2" }, N = { class: "flex items-center gap-2 min-w-0" }, P = { class: "text-sm font-medium text-gray-800 truncate" }, F = {
67
+ key: 0,
68
+ class: "text-[10px] uppercase tracking-wide rounded px-1.5 py-0.5 bg-blue-50 text-blue-700 shrink-0"
69
+ }, I = ["data-testid", "onClick"], L = ["data-testid"], R = /* @__PURE__ */ d({
70
+ __name: "View",
71
+ props: { selectedResult: {} },
72
+ setup(e) {
73
+ let t = T(), n = e, r = o(() => n.selectedResult.data), i = o(() => r.value?.document?.charts ?? []), d = o(() => r.value?.title ?? r.value?.document?.title), f = g([]), S = [];
74
+ function C(e) {
75
+ return typeof e == "object" && !!e && !Array.isArray(e);
76
+ }
77
+ function w(e, t) {
78
+ f.value[e] = t;
79
+ }
80
+ function R() {
81
+ for (let e of S) e.dispose();
82
+ S.length = 0;
83
+ }
84
+ function z(e) {
85
+ let { dataZoom: t } = e;
86
+ if (t == null) return e;
87
+ let n = (e) => C(e) ? {
88
+ ...e,
89
+ zoomOnMouseWheel: !1,
90
+ moveOnMouseWheel: !1
91
+ } : e, r = Array.isArray(t) ? t.map(n) : n(t);
92
+ return {
93
+ ...e,
94
+ dataZoom: r
95
+ };
96
+ }
97
+ function B() {
98
+ R();
99
+ for (let e = 0; e < i.value.length; e += 1) {
100
+ let t = f.value[e], n = i.value[e];
101
+ if (!t || !n) continue;
102
+ let r = x.init(t);
103
+ try {
104
+ r.setOption(z(n.option));
105
+ } catch {}
106
+ S[e] = r;
107
+ }
108
+ }
109
+ function V() {
110
+ for (let e of S) e.resize();
111
+ }
112
+ m(() => {
113
+ queueMicrotask(B), window.addEventListener("resize", V);
114
+ }), p(() => {
115
+ window.removeEventListener("resize", V), R();
116
+ }), b(() => r.value?.filePath, () => queueMicrotask(B));
117
+ function H(e, t) {
118
+ let n = S[e];
119
+ if (!n) return;
120
+ let r = n.getDataURL({
121
+ type: "png",
122
+ pixelRatio: 2,
123
+ backgroundColor: "#ffffff"
124
+ }), i = (t ?? d.value ?? "chart").toLowerCase().replace(/[^a-z0-9-]+/g, "-");
125
+ for (; i.startsWith("-");) i = i.slice(1);
126
+ for (; i.endsWith("-");) i = i.slice(0, -1);
127
+ i ||= "chart";
128
+ let a = document.createElement("a");
129
+ a.href = r, a.download = `${i}-${e + 1}.png`, document.body.appendChild(a), a.click(), document.body.removeChild(a);
130
+ }
131
+ return (e, n) => (h(), c("div", E, [l("div", D, [l("span", O, v(d.value ?? y(t).untitled), 1), l("span", k, v(y(t).chartCount(i.value.length)), 1)]), l("div", A, [(h(!0), c(a, null, _(i.value, (e, r) => (h(), c("div", {
132
+ key: r,
133
+ class: "border border-gray-200 rounded-lg bg-white",
134
+ "data-testid": `chart-card-${r}`
135
+ }, [l("div", M, [l("div", N, [l("span", P, v(e.title ?? y(t).chartTitle(r + 1)), 1), e.type ? (h(), c("span", F, v(e.type), 1)) : s("", !0)]), l("button", {
136
+ class: "px-2 py-1 text-xs rounded border border-gray-300 text-gray-500 hover:bg-gray-50 shrink-0",
137
+ "data-testid": `chart-export-png-${r}`,
138
+ onClick: (t) => H(r, e.title)
139
+ }, [n[0] ||= l("span", { class: "material-icons text-sm align-middle" }, "download", -1), u(" " + v(y(t).png), 1)], 8, I)]), l("div", {
140
+ ref_for: !0,
141
+ ref: (e) => w(r, e),
142
+ class: "w-full h-[400px]",
143
+ "data-testid": `chart-canvas-${r}`
144
+ }, null, 8, L)], 8, j))), 128))])]));
145
+ }
146
+ }), z = { class: "p-2 text-sm" }, B = { class: "font-medium text-gray-700 truncate mb-1" }, V = {
147
+ key: 0,
148
+ class: "text-xs text-gray-500 leading-relaxed truncate"
149
+ }, H = /* @__PURE__ */ d({
150
+ __name: "Preview",
151
+ props: { result: {} },
152
+ setup(e) {
153
+ let t = e, n = o(() => t.result.data), r = o(() => n.value?.title ?? n.value?.document?.title ?? "Chart"), i = o(() => {
154
+ let e = n.value?.document?.charts ?? [];
155
+ if (e.length === 0) return "";
156
+ let t = e.map((e) => e.type ?? a(e.option)).filter((e) => !!e).slice(0, 3), r = e.length > t.length ? ", …" : "", i = t.join(", "), o = e.length === 1 ? "" : "s", s = i ? `: ${i}${r}` : "";
157
+ return `${e.length} chart${o}${s}`;
158
+ });
159
+ function a(e) {
160
+ let { series: t } = e;
161
+ if (Array.isArray(t) && t.length > 0) {
162
+ let e = t[0];
163
+ if (typeof e.type == "string") return e.type;
164
+ } else if (t && typeof t == "object") {
165
+ let e = t.type;
166
+ if (typeof e == "string") return e;
167
+ }
168
+ return null;
169
+ }
170
+ return (e, t) => (h(), c("div", z, [l("div", B, v(r.value), 1), i.value ? (h(), c("div", V, v(i.value), 1)) : s("", !0)]));
171
+ }
172
+ }), U = {
173
+ ...n,
174
+ viewComponent: R,
175
+ previewComponent: H
176
+ }, W = { plugin: U };
177
+ //#endregion
178
+ export { H as Preview, t as TOOL_DEFINITION, r as TOOL_NAME, R as View, W as default, i as executeChart, e as isValidChartDocument, U as plugin, n as pluginCore };
package/package.json ADDED
@@ -0,0 +1,62 @@
1
+ {
2
+ "name": "@mulmoclaude/chart-plugin",
3
+ "version": "0.1.0",
4
+ "description": "ECharts visualization plugin (presentChart) — shared gui-chat-protocol plugin for MulmoClaude and MulmoTerminal. Server-side write goes through the generic files.artifacts runtime capability.",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.js",
13
+ "require": "./dist/index.cjs",
14
+ "default": "./dist/index.js"
15
+ },
16
+ "./vue": {
17
+ "types": "./dist/vue/index.d.ts",
18
+ "import": "./dist/vue.js",
19
+ "require": "./dist/vue.cjs",
20
+ "default": "./dist/vue.js"
21
+ },
22
+ "./style.css": "./dist/style.css"
23
+ },
24
+ "files": [
25
+ "dist"
26
+ ],
27
+ "publishConfig": {
28
+ "access": "public"
29
+ },
30
+ "scripts": {
31
+ "build": "vite build && vue-tsc -p tsconfig.build.json --emitDeclarationOnly",
32
+ "prepack": "vite build && vue-tsc -p tsconfig.build.json --emitDeclarationOnly",
33
+ "typecheck": "vue-tsc --noEmit",
34
+ "lint": "eslint .",
35
+ "test": "echo 'no in-package tests; presentChart logic is covered by host integration tests'"
36
+ },
37
+ "peerDependencies": {
38
+ "echarts": "^6.0.0",
39
+ "gui-chat-protocol": "^0.4.0",
40
+ "vue": "^3.5.0"
41
+ },
42
+ "devDependencies": {
43
+ "@eslint/js": "^10.0.1",
44
+ "@tailwindcss/vite": "^4.2.2",
45
+ "@types/node": "^25.5.0",
46
+ "@typescript-eslint/eslint-plugin": "^8.58.0",
47
+ "@typescript-eslint/parser": "^8.58.0",
48
+ "@vitejs/plugin-vue": "^6.0.5",
49
+ "echarts": "^6.0.0",
50
+ "eslint": "^10.1.0",
51
+ "eslint-plugin-vue": "^10.8.0",
52
+ "globals": "^17.4.0",
53
+ "gui-chat-protocol": "^0.4.0",
54
+ "tailwindcss": "^4.2.2",
55
+ "typescript": "~6.0.2",
56
+ "vite": "^8.0.3",
57
+ "vue": "^3.5.31",
58
+ "vue-eslint-parser": "^10.4.0",
59
+ "vue-tsc": "^3.2.6"
60
+ },
61
+ "license": "MIT"
62
+ }