@gui-chat-plugin/music 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,90 @@
1
+ # @gui-chat-plugin/music
2
+
3
+ MusicXML sheet music plugin for GUI Chat applications. Displays and plays sheet music from MusicXML format.
4
+
5
+ ## Features
6
+
7
+ - Display sheet music from MusicXML format
8
+ - Audio playback with OpenSheetMusicDisplay and osmd-audio-player
9
+ - Tempo control
10
+ - Cursor following during playback
11
+
12
+ ## Installation
13
+
14
+ ```bash
15
+ yarn add @gui-chat-plugin/music
16
+ ```
17
+
18
+ ## Usage
19
+
20
+ ### Vue Integration
21
+
22
+ ```typescript
23
+ // In src/tools/index.ts
24
+ import MusicPlugin from "@gui-chat-plugin/music/vue";
25
+
26
+ const pluginList = [
27
+ // ... other plugins
28
+ MusicPlugin,
29
+ ];
30
+
31
+ // In src/main.ts
32
+ import "@gui-chat-plugin/music/style.css";
33
+ ```
34
+
35
+ ### Core-only Usage
36
+
37
+ ```typescript
38
+ import { executeMusic, TOOL_DEFINITION } from "@gui-chat-plugin/music";
39
+
40
+ // Show sheet music
41
+ const result = await executeMusic(context, {
42
+ musicXML: "<musicxml-content>",
43
+ title: "My Song",
44
+ });
45
+ ```
46
+
47
+ ## API
48
+
49
+ ### MusicArgs
50
+
51
+ ```typescript
52
+ interface MusicArgs {
53
+ musicXML: string; // The music in MusicXML format
54
+ title?: string; // Optional title for the music piece
55
+ }
56
+ ```
57
+
58
+ ### MusicToolData
59
+
60
+ ```typescript
61
+ interface MusicToolData {
62
+ musicXML: string;
63
+ }
64
+ ```
65
+
66
+ ## Dependencies
67
+
68
+ This plugin requires:
69
+ - `opensheetmusicdisplay`: For rendering MusicXML as sheet music
70
+ - `osmd-audio-player`: For audio playback
71
+
72
+ ## Development
73
+
74
+ ```bash
75
+ # Install dependencies
76
+ yarn install
77
+
78
+ # Run demo
79
+ yarn dev
80
+
81
+ # Build
82
+ yarn build
83
+
84
+ # Lint
85
+ yarn lint
86
+ ```
87
+
88
+ ## License
89
+
90
+ MIT
@@ -0,0 +1,20 @@
1
+ export declare const TOOL_NAME = "showMusic";
2
+ export declare const TOOL_DEFINITION: {
3
+ type: "function";
4
+ name: string;
5
+ description: string;
6
+ parameters: {
7
+ type: "object";
8
+ properties: {
9
+ musicXML: {
10
+ type: string;
11
+ description: string;
12
+ };
13
+ title: {
14
+ type: string;
15
+ description: string;
16
+ };
17
+ };
18
+ required: string[];
19
+ };
20
+ };
@@ -0,0 +1,4 @@
1
+ export * from "./types";
2
+ export * from "./definition";
3
+ export * from "./plugin";
4
+ export * from "./samples";
@@ -0,0 +1,6 @@
1
+ import type { ToolContext, ToolResult } from "gui-chat-protocol/vue";
2
+ import type { MusicToolData, MusicArgs } from "./types";
3
+ import { TOOL_DEFINITION } from "./definition";
4
+ export type MusicResult = ToolResult<MusicToolData>;
5
+ export declare const showMusic: (_context: ToolContext, args: MusicArgs) => Promise<MusicResult>;
6
+ export { TOOL_DEFINITION };
@@ -0,0 +1,2 @@
1
+ import type { ToolSample } from "gui-chat-protocol";
2
+ export declare const samples: ToolSample[];
@@ -0,0 +1,8 @@
1
+ export interface MusicToolData {
2
+ musicXML: string;
3
+ }
4
+ export interface MusicArgs {
5
+ musicXML: string;
6
+ title?: string;
7
+ }
8
+ export type { ToolResult } from "gui-chat-protocol/vue";
package/dist/core.cjs ADDED
@@ -0,0 +1,94 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e="showMusic",s={type:"function",name:e,description:"Display sheet music from MusicXML format.",parameters:{type:"object",properties:{musicXML:{type:"string",description:"The music in MusicXML format"},title:{type:"string",description:"Optional title for the music piece"}},required:["musicXML"]}},o=async(c,i)=>{try{const{musicXML:t,title:r}=i;if(!t||typeof t!="string")throw new Error("musicXML parameter is required and must be a string");return{message:"Sheet music displayed",title:r||"Sheet Music",data:{musicXML:t},instructions:"Acknowledge that the sheet music has been displayed to the user."}}catch(t){return console.error(`ERR: exception
2
+ Music rendering failed`,t),{message:`Music rendering failed: ${t instanceof Error?t.message:"Unknown error"}`,instructions:"Acknowledge that the music rendering failed."}}},a=`<?xml version="1.0" encoding="UTF-8"?>
3
+ <!DOCTYPE score-partwise PUBLIC "-//Recordare//DTD MusicXML 3.1 Partwise//EN" "http://www.musicxml.org/dtds/partwise.dtd">
4
+ <score-partwise version="3.1">
5
+ <part-list>
6
+ <score-part id="P1">
7
+ <part-name>Piano</part-name>
8
+ </score-part>
9
+ </part-list>
10
+ <part id="P1">
11
+ <measure number="1">
12
+ <attributes>
13
+ <divisions>1</divisions>
14
+ <key>
15
+ <fifths>0</fifths>
16
+ </key>
17
+ <time>
18
+ <beats>4</beats>
19
+ <beat-type>4</beat-type>
20
+ </time>
21
+ <clef>
22
+ <sign>G</sign>
23
+ <line>2</line>
24
+ </clef>
25
+ </attributes>
26
+ <note>
27
+ <pitch>
28
+ <step>C</step>
29
+ <octave>4</octave>
30
+ </pitch>
31
+ <duration>1</duration>
32
+ <type>quarter</type>
33
+ </note>
34
+ <note>
35
+ <pitch>
36
+ <step>D</step>
37
+ <octave>4</octave>
38
+ </pitch>
39
+ <duration>1</duration>
40
+ <type>quarter</type>
41
+ </note>
42
+ <note>
43
+ <pitch>
44
+ <step>E</step>
45
+ <octave>4</octave>
46
+ </pitch>
47
+ <duration>1</duration>
48
+ <type>quarter</type>
49
+ </note>
50
+ <note>
51
+ <pitch>
52
+ <step>F</step>
53
+ <octave>4</octave>
54
+ </pitch>
55
+ <duration>1</duration>
56
+ <type>quarter</type>
57
+ </note>
58
+ </measure>
59
+ <measure number="2">
60
+ <note>
61
+ <pitch>
62
+ <step>G</step>
63
+ <octave>4</octave>
64
+ </pitch>
65
+ <duration>1</duration>
66
+ <type>quarter</type>
67
+ </note>
68
+ <note>
69
+ <pitch>
70
+ <step>A</step>
71
+ <octave>4</octave>
72
+ </pitch>
73
+ <duration>1</duration>
74
+ <type>quarter</type>
75
+ </note>
76
+ <note>
77
+ <pitch>
78
+ <step>B</step>
79
+ <octave>4</octave>
80
+ </pitch>
81
+ <duration>1</duration>
82
+ <type>quarter</type>
83
+ </note>
84
+ <note>
85
+ <pitch>
86
+ <step>C</step>
87
+ <octave>5</octave>
88
+ </pitch>
89
+ <duration>1</duration>
90
+ <type>quarter</type>
91
+ </note>
92
+ </measure>
93
+ </part>
94
+ </score-partwise>`,n=[{name:"C Major Scale",args:{musicXML:a,title:"C Major Scale"}}];exports.TOOL_DEFINITION=s;exports.TOOL_NAME=e;exports.samples=n;exports.showMusic=o;
package/dist/core.js ADDED
@@ -0,0 +1,143 @@
1
+ const r = "showMusic", o = {
2
+ type: "function",
3
+ name: r,
4
+ description: "Display sheet music from MusicXML format.",
5
+ parameters: {
6
+ type: "object",
7
+ properties: {
8
+ musicXML: {
9
+ type: "string",
10
+ description: "The music in MusicXML format"
11
+ },
12
+ title: {
13
+ type: "string",
14
+ description: "Optional title for the music piece"
15
+ }
16
+ },
17
+ required: ["musicXML"]
18
+ }
19
+ }, n = async (a, e) => {
20
+ try {
21
+ const { musicXML: t, title: i } = e;
22
+ if (!t || typeof t != "string")
23
+ throw new Error("musicXML parameter is required and must be a string");
24
+ return {
25
+ message: "Sheet music displayed",
26
+ title: i || "Sheet Music",
27
+ data: { musicXML: t },
28
+ instructions: "Acknowledge that the sheet music has been displayed to the user."
29
+ };
30
+ } catch (t) {
31
+ return console.error(`ERR: exception
32
+ Music rendering failed`, t), {
33
+ message: `Music rendering failed: ${t instanceof Error ? t.message : "Unknown error"}`,
34
+ instructions: "Acknowledge that the music rendering failed."
35
+ };
36
+ }
37
+ }, s = `<?xml version="1.0" encoding="UTF-8"?>
38
+ <!DOCTYPE score-partwise PUBLIC "-//Recordare//DTD MusicXML 3.1 Partwise//EN" "http://www.musicxml.org/dtds/partwise.dtd">
39
+ <score-partwise version="3.1">
40
+ <part-list>
41
+ <score-part id="P1">
42
+ <part-name>Piano</part-name>
43
+ </score-part>
44
+ </part-list>
45
+ <part id="P1">
46
+ <measure number="1">
47
+ <attributes>
48
+ <divisions>1</divisions>
49
+ <key>
50
+ <fifths>0</fifths>
51
+ </key>
52
+ <time>
53
+ <beats>4</beats>
54
+ <beat-type>4</beat-type>
55
+ </time>
56
+ <clef>
57
+ <sign>G</sign>
58
+ <line>2</line>
59
+ </clef>
60
+ </attributes>
61
+ <note>
62
+ <pitch>
63
+ <step>C</step>
64
+ <octave>4</octave>
65
+ </pitch>
66
+ <duration>1</duration>
67
+ <type>quarter</type>
68
+ </note>
69
+ <note>
70
+ <pitch>
71
+ <step>D</step>
72
+ <octave>4</octave>
73
+ </pitch>
74
+ <duration>1</duration>
75
+ <type>quarter</type>
76
+ </note>
77
+ <note>
78
+ <pitch>
79
+ <step>E</step>
80
+ <octave>4</octave>
81
+ </pitch>
82
+ <duration>1</duration>
83
+ <type>quarter</type>
84
+ </note>
85
+ <note>
86
+ <pitch>
87
+ <step>F</step>
88
+ <octave>4</octave>
89
+ </pitch>
90
+ <duration>1</duration>
91
+ <type>quarter</type>
92
+ </note>
93
+ </measure>
94
+ <measure number="2">
95
+ <note>
96
+ <pitch>
97
+ <step>G</step>
98
+ <octave>4</octave>
99
+ </pitch>
100
+ <duration>1</duration>
101
+ <type>quarter</type>
102
+ </note>
103
+ <note>
104
+ <pitch>
105
+ <step>A</step>
106
+ <octave>4</octave>
107
+ </pitch>
108
+ <duration>1</duration>
109
+ <type>quarter</type>
110
+ </note>
111
+ <note>
112
+ <pitch>
113
+ <step>B</step>
114
+ <octave>4</octave>
115
+ </pitch>
116
+ <duration>1</duration>
117
+ <type>quarter</type>
118
+ </note>
119
+ <note>
120
+ <pitch>
121
+ <step>C</step>
122
+ <octave>5</octave>
123
+ </pitch>
124
+ <duration>1</duration>
125
+ <type>quarter</type>
126
+ </note>
127
+ </measure>
128
+ </part>
129
+ </score-partwise>`, c = [
130
+ {
131
+ name: "C Major Scale",
132
+ args: {
133
+ musicXML: s,
134
+ title: "C Major Scale"
135
+ }
136
+ }
137
+ ];
138
+ export {
139
+ o as TOOL_DEFINITION,
140
+ r as TOOL_NAME,
141
+ c as samples,
142
+ n as showMusic
143
+ };
package/dist/index.cjs ADDED
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./core.cjs");exports.TOOL_DEFINITION=e.TOOL_DEFINITION;exports.TOOL_NAME=e.TOOL_NAME;exports.samples=e.samples;exports.showMusic=e.showMusic;
@@ -0,0 +1 @@
1
+ export * from "./core";
package/dist/index.js ADDED
@@ -0,0 +1,7 @@
1
+ import { TOOL_DEFINITION as o, TOOL_NAME as I, samples as N, showMusic as T } from "./core.js";
2
+ export {
3
+ o as TOOL_DEFINITION,
4
+ I as TOOL_NAME,
5
+ N as samples,
6
+ T as showMusic
7
+ };
package/dist/style.css ADDED
@@ -0,0 +1 @@
1
+ @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-border-style:solid;--tw-font-weight:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000}}}@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-red-500:oklch(63.7% .237 25.331);--color-blue-500:oklch(62.3% .214 259.815);--color-indigo-100:oklch(93% .034 272.788);--color-indigo-200:oklch(87% .065 274.039);--color-indigo-700:oklch(45.7% .24 277.023);--color-purple-50:oklch(97.7% .014 308.299);--color-purple-600:oklch(55.8% .288 302.321);--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-600:oklch(44.6% .03 256.802);--color-gray-700:oklch(37.3% .034 259.733);--color-gray-800:oklch(27.8% .033 256.848);--color-gray-900:oklch(21% .034 264.665);--color-white:#fff;--spacing:.25rem;--container-3xl:48rem;--text-xs:.75rem;--text-xs--line-height:calc(1/.75);--text-sm:.875rem;--text-sm--line-height:calc(1.25/.875);--text-xl:1.25rem;--text-xl--line-height:calc(1.75/1.25);--text-2xl:1.5rem;--text-2xl--line-height:calc(2/1.5);--font-weight-medium:500;--font-weight-bold:700;--radius-md:.375rem;--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;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{.mx-auto{margin-inline:auto}.mt-1{margin-top:calc(var(--spacing)*1)}.mb-4{margin-bottom:calc(var(--spacing)*4)}.mb-5{margin-bottom:calc(var(--spacing)*5)}.mb-8{margin-bottom:calc(var(--spacing)*8)}.contents{display:contents}.flex{display:flex}.h-\[600px\]{height:600px}.h-full{height:100%}.min-h-full{min-height:100%}.w-20{width:calc(var(--spacing)*20)}.w-full{width:100%}.max-w-3xl{max-width:var(--container-3xl)}.max-w-\[200px\]{max-width:200px}.flex-1{flex:1}.cursor-pointer{cursor:pointer}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-center{align-items:center}.justify-center{justify-content:center}.gap-1{gap:calc(var(--spacing)*1)}.gap-2{gap:calc(var(--spacing)*2)}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.overflow-y-auto{overflow-y:auto}.rounded{border-radius:.25rem}.rounded-lg{border-radius:var(--radius-lg)}.rounded-md{border-radius:var(--radius-md)}.border{border-style:var(--tw-border-style);border-width:1px}.border-gray-300{border-color:var(--color-gray-300)}.border-gray-600{border-color:var(--color-gray-600)}.border-indigo-200{border-color:var(--color-indigo-200)}.bg-blue-500{background-color:var(--color-blue-500)}.bg-gray-100{background-color:var(--color-gray-100)}.bg-gray-800{background-color:var(--color-gray-800)}.bg-indigo-100{background-color:var(--color-indigo-100)}.bg-purple-50{background-color:var(--color-purple-50)}.bg-red-500{background-color:var(--color-red-500)}.bg-white{background-color:var(--color-white)}.p-4{padding:calc(var(--spacing)*4)}.p-5{padding:calc(var(--spacing)*5)}.p-8{padding:calc(var(--spacing)*8)}.px-2{padding-inline:calc(var(--spacing)*2)}.px-4{padding-inline:calc(var(--spacing)*4)}.py-1{padding-block:calc(var(--spacing)*1)}.py-2{padding-block:calc(var(--spacing)*2)}.text-center{text-align:center}.text-2xl{font-size:var(--text-2xl);line-height:var(--tw-leading,var(--text-2xl--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xl{font-size:var(--text-xl);line-height:var(--tw-leading,var(--text-xl--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.font-bold{--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.text-gray-200{color:var(--color-gray-200)}.text-gray-600{color:var(--color-gray-600)}.text-gray-700{color:var(--color-gray-700)}.text-gray-800{color:var(--color-gray-800)}.text-gray-900{color:var(--color-gray-900)}.text-indigo-700{color:var(--color-indigo-700)}.text-purple-600{color:var(--color-purple-600)}.text-red-500{color:var(--color-red-500)}.text-white{color:var(--color-white)}.shadow-md{--tw-shadow:0 4px 6px -1px var(--tw-shadow-color,#0000001a),0 2px 4px -2px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}@media(hover:hover){.hover\:bg-indigo-200:hover{background-color:var(--color-indigo-200)}}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:bg-gray-300:disabled{background-color:var(--color-gray-300)}}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}
@@ -0,0 +1,8 @@
1
+ import type { ToolResult } from "gui-chat-protocol/vue";
2
+ import type { MusicToolData } from "../core/types";
3
+ type __VLS_Props = {
4
+ result: ToolResult<MusicToolData>;
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;
@@ -0,0 +1,9 @@
1
+ import type { ToolResult } from "gui-chat-protocol/vue";
2
+ import type { MusicToolData } from "../core/types";
3
+ type __VLS_Props = {
4
+ selectedResult: ToolResult<MusicToolData>;
5
+ sendTextMessage: (text?: string) => void;
6
+ };
7
+ 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>;
8
+ declare const _default: typeof __VLS_export;
9
+ export default _default;
@@ -0,0 +1,11 @@
1
+ import "../style.css";
2
+ import type { ToolPlugin } from "gui-chat-protocol/vue";
3
+ import type { MusicToolData, MusicArgs } from "../core/types";
4
+ export declare const plugin: ToolPlugin<MusicToolData, unknown, MusicArgs>;
5
+ export { showMusic as executeMusic } from "../core/plugin";
6
+ export * from "../core/types";
7
+ export { TOOL_DEFINITION } from "../core/definition";
8
+ declare const _default: {
9
+ plugin: ToolPlugin<MusicToolData, unknown, MusicArgs, import("gui-chat-protocol/vue").InputHandler, Record<string, unknown>>;
10
+ };
11
+ export default _default;
package/dist/vue.cjs ADDED
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const c=require("./core.cjs"),e=require("vue"),h=require("opensheetmusicdisplay"),w=require("osmd-audio-player"),b={class:"w-full h-full overflow-y-auto"},E={class:"min-h-full flex flex-col p-4"},M={key:0,class:"mb-4 text-center"},_={class:"text-2xl font-bold text-gray-900"},N={class:"mb-4 flex gap-2 items-center justify-center"},T=["disabled"],V={class:"text-xl"},k={class:"flex items-center gap-2"},S=e.defineComponent({__name:"View",props:{selectedResult:{},sendTextMessage:{type:Function}},setup(r){const d=r,l=e.ref(null);let i=null,t=null;const m=e.ref(!1),o=e.ref(!1),a=e.ref(200),p=e.ref(!1),f=e.ref(!1),v=async()=>{if(!(!l.value||!d.selectedResult.data?.musicXML))try{l.value.innerHTML="",m.value=!1,o.value=!1,i=new h.OpenSheetMusicDisplay(l.value,{autoResize:!0,backend:"svg",drawTitle:!1,followCursor:!0}),await i.load(d.selectedResult.data.musicXML),await i.render(),t||(t=new w),await t.loadScore(i);const n=i.Sheet?.SourceMeasures?.[0]?.TempoExpressions;if(n&&n.length>0){const s=n[0],u=s.TempoInBpm||s.tempoInBpm;u&&(a.value=u)}t.on("iteration",s=>{!p.value&&s&&s.length===0&&(t.stop(),o.value=!1)}),m.value=!0}catch(n){console.error("Error rendering music:",n),l.value&&(l.value.innerHTML=`<div class="text-red-500">Error rendering sheet music: ${n instanceof Error?n.message:"Unknown error"}</div>`)}},x=async()=>{!t||!m.value||(t.setBpm(Math.max(30,Math.min(300,a.value))),t.metronomeVolume=f.value?.7:0,t.isLooping=p.value,await t.play(),o.value=!0)},y=()=>{t&&(t.stop(),o.value=!1)};return e.watch(a,()=>{t&&t.setBpm(Math.max(30,Math.min(300,a.value)))}),e.watch(p,()=>{t&&(t.isLooping=p.value)}),e.watch(f,()=>{t&&(t.metronomeVolume=f.value?.7:0)}),e.onMounted(()=>{v()}),e.watch(()=>d.selectedResult.data?.musicXML,()=>{v()}),e.onUnmounted(()=>{t&&t.stop()}),(n,s)=>(e.openBlock(),e.createElementBlock("div",b,[e.createElementVNode("div",E,[r.selectedResult.title?(e.openBlock(),e.createElementBlock("div",M,[e.createElementVNode("h2",_,e.toDisplayString(r.selectedResult.title),1)])):e.createCommentVNode("",!0),e.createElementVNode("div",N,[e.createElementVNode("button",{onClick:s[0]||(s[0]=u=>o.value?y():x()),disabled:!m.value,class:e.normalizeClass(["px-4 py-2 text-white rounded disabled:bg-gray-300 disabled:cursor-not-allowed flex items-center gap-1",o.value?"bg-red-500":"bg-blue-500"])},[e.createElementVNode("span",V,e.toDisplayString(o.value?"⏹":"▶"),1),e.createTextVNode(" "+e.toDisplayString(o.value?"Stop":"Play"),1)],10,T),e.createElementVNode("label",k,[s[2]||(s[2]=e.createTextVNode(" Tempo ",-1)),e.withDirectives(e.createElementVNode("input",{"onUpdate:modelValue":s[1]||(s[1]=u=>a.value=u),type:"number",min:"30",max:"300",class:"w-20 px-2 py-1 border border-gray-300 rounded"},null,512),[[e.vModelText,a.value,void 0,{number:!0}]]),s[3]||(s[3]=e.createTextVNode(" bpm ",-1))])]),e.createElementVNode("div",{ref_key:"musicContainer",ref:l,class:"flex-1 flex items-center justify-center bg-white rounded-lg p-4"},null,512)])]))}}),B={class:"text-center p-4 bg-purple-50 rounded"},C={key:0,class:"text-xs text-gray-600 mt-1 truncate"},I=e.defineComponent({__name:"Preview",props:{result:{}},setup(r){return(d,l)=>(e.openBlock(),e.createElementBlock("div",B,[l[0]||(l[0]=e.createElementVNode("div",{class:"text-purple-600 font-medium"},"🎵 Sheet Music",-1)),r.result.title?(e.openBlock(),e.createElementBlock("div",C,e.toDisplayString(r.result.title),1)):e.createCommentVNode("",!0)]))}}),g={toolDefinition:c.TOOL_DEFINITION,execute:c.showMusic,generatingMessage:"Rendering sheet music...",isEnabled:()=>!0,viewComponent:S,previewComponent:I,samples:c.samples},L={plugin:g};exports.TOOL_DEFINITION=c.TOOL_DEFINITION;exports.executeMusic=c.showMusic;exports.default=L;exports.plugin=g;
package/dist/vue.js ADDED
@@ -0,0 +1,126 @@
1
+ import { samples as k, showMusic as C, TOOL_DEFINITION as E } from "./core.js";
2
+ import { defineComponent as w, ref as i, watch as f, onMounted as L, onUnmounted as R, createElementBlock as x, openBlock as g, createElementVNode as l, createCommentVNode as M, toDisplayString as v, normalizeClass as S, createTextVNode as h, withDirectives as V, vModelText as B } from "vue";
3
+ import { OpenSheetMusicDisplay as D } from "opensheetmusicdisplay";
4
+ import I from "osmd-audio-player";
5
+ const N = { class: "w-full h-full overflow-y-auto" }, P = { class: "min-h-full flex flex-col p-4" }, $ = {
6
+ key: 0,
7
+ class: "mb-4 text-center"
8
+ }, O = { class: "text-2xl font-bold text-gray-900" }, U = { class: "mb-4 flex gap-2 items-center justify-center" }, X = ["disabled"], j = { class: "text-xl" }, z = { class: "flex items-center gap-2" }, F = /* @__PURE__ */ w({
9
+ __name: "View",
10
+ props: {
11
+ selectedResult: {},
12
+ sendTextMessage: { type: Function }
13
+ },
14
+ setup(a) {
15
+ const d = a, s = i(null);
16
+ let u = null, e = null;
17
+ const m = i(!1), o = i(!1), r = i(200), p = i(!1), y = i(!1), b = async () => {
18
+ if (!(!s.value || !d.selectedResult.data?.musicXML))
19
+ try {
20
+ s.value.innerHTML = "", m.value = !1, o.value = !1, u = new D(s.value, {
21
+ autoResize: !0,
22
+ backend: "svg",
23
+ drawTitle: !1,
24
+ followCursor: !0
25
+ }), await u.load(d.selectedResult.data.musicXML), await u.render(), e || (e = new I()), await e.loadScore(u);
26
+ const n = u.Sheet?.SourceMeasures?.[0]?.TempoExpressions;
27
+ if (n && n.length > 0) {
28
+ const t = n[0], c = t.TempoInBpm || t.tempoInBpm;
29
+ c && (r.value = c);
30
+ }
31
+ e.on("iteration", (t) => {
32
+ !p.value && t && t.length === 0 && (e.stop(), o.value = !1);
33
+ }), m.value = !0;
34
+ } catch (n) {
35
+ console.error("Error rendering music:", n), s.value && (s.value.innerHTML = `<div class="text-red-500">Error rendering sheet music: ${n instanceof Error ? n.message : "Unknown error"}</div>`);
36
+ }
37
+ }, _ = async () => {
38
+ !e || !m.value || (e.setBpm(Math.max(30, Math.min(300, r.value))), e.metronomeVolume = y.value ? 0.7 : 0, e.isLooping = p.value, await e.play(), o.value = !0);
39
+ }, T = () => {
40
+ e && (e.stop(), o.value = !1);
41
+ };
42
+ return f(r, () => {
43
+ e && e.setBpm(Math.max(30, Math.min(300, r.value)));
44
+ }), f(p, () => {
45
+ e && (e.isLooping = p.value);
46
+ }), f(y, () => {
47
+ e && (e.metronomeVolume = y.value ? 0.7 : 0);
48
+ }), L(() => {
49
+ b();
50
+ }), f(
51
+ () => d.selectedResult.data?.musicXML,
52
+ () => {
53
+ b();
54
+ }
55
+ ), R(() => {
56
+ e && e.stop();
57
+ }), (n, t) => (g(), x("div", N, [
58
+ l("div", P, [
59
+ a.selectedResult.title ? (g(), x("div", $, [
60
+ l("h2", O, v(a.selectedResult.title), 1)
61
+ ])) : M("", !0),
62
+ l("div", U, [
63
+ l("button", {
64
+ onClick: t[0] || (t[0] = (c) => o.value ? T() : _()),
65
+ disabled: !m.value,
66
+ class: S(["px-4 py-2 text-white rounded disabled:bg-gray-300 disabled:cursor-not-allowed flex items-center gap-1", o.value ? "bg-red-500" : "bg-blue-500"])
67
+ }, [
68
+ l("span", j, v(o.value ? "⏹" : "▶"), 1),
69
+ h(" " + v(o.value ? "Stop" : "Play"), 1)
70
+ ], 10, X),
71
+ l("label", z, [
72
+ t[2] || (t[2] = h(" Tempo ", -1)),
73
+ V(l("input", {
74
+ "onUpdate:modelValue": t[1] || (t[1] = (c) => r.value = c),
75
+ type: "number",
76
+ min: "30",
77
+ max: "300",
78
+ class: "w-20 px-2 py-1 border border-gray-300 rounded"
79
+ }, null, 512), [
80
+ [
81
+ B,
82
+ r.value,
83
+ void 0,
84
+ { number: !0 }
85
+ ]
86
+ ]),
87
+ t[3] || (t[3] = h(" bpm ", -1))
88
+ ])
89
+ ]),
90
+ l("div", {
91
+ ref_key: "musicContainer",
92
+ ref: s,
93
+ class: "flex-1 flex items-center justify-center bg-white rounded-lg p-4"
94
+ }, null, 512)
95
+ ])
96
+ ]));
97
+ }
98
+ }), H = { class: "text-center p-4 bg-purple-50 rounded" }, q = {
99
+ key: 0,
100
+ class: "text-xs text-gray-600 mt-1 truncate"
101
+ }, A = /* @__PURE__ */ w({
102
+ __name: "Preview",
103
+ props: {
104
+ result: {}
105
+ },
106
+ setup(a) {
107
+ return (d, s) => (g(), x("div", H, [
108
+ s[0] || (s[0] = l("div", { class: "text-purple-600 font-medium" }, "🎵 Sheet Music", -1)),
109
+ a.result.title ? (g(), x("div", q, v(a.result.title), 1)) : M("", !0)
110
+ ]));
111
+ }
112
+ }), G = {
113
+ toolDefinition: E,
114
+ execute: C,
115
+ generatingMessage: "Rendering sheet music...",
116
+ isEnabled: () => !0,
117
+ viewComponent: F,
118
+ previewComponent: A,
119
+ samples: k
120
+ }, Y = { plugin: G };
121
+ export {
122
+ E as TOOL_DEFINITION,
123
+ Y as default,
124
+ C as executeMusic,
125
+ G as plugin
126
+ };
package/package.json ADDED
@@ -0,0 +1,59 @@
1
+ {
2
+ "name": "@gui-chat-plugin/music",
3
+ "version": "0.0.1",
4
+ "description": "MusicXML sheet music plugin for GUI Chat",
5
+ "type": "module",
6
+ "main": "./dist/index.cjs",
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
+ },
15
+ "./core": {
16
+ "types": "./dist/core/index.d.ts",
17
+ "import": "./dist/core.js",
18
+ "require": "./dist/core.cjs"
19
+ },
20
+ "./vue": {
21
+ "types": "./dist/vue/index.d.ts",
22
+ "import": "./dist/vue.js",
23
+ "require": "./dist/vue.cjs"
24
+ },
25
+ "./style.css": "./dist/style.css"
26
+ },
27
+ "files": ["dist"],
28
+ "scripts": {
29
+ "dev": "vite",
30
+ "build": "vite build && vue-tsc -p tsconfig.build.json --emitDeclarationOnly",
31
+ "typecheck": "vue-tsc --noEmit",
32
+ "lint": "eslint src demo"
33
+ },
34
+ "peerDependencies": {
35
+ "vue": "^3.5.0"
36
+ },
37
+ "dependencies": {
38
+ "gui-chat-protocol": "^0.0.1",
39
+ "opensheetmusicdisplay": "^1.9.3",
40
+ "osmd-audio-player": "^0.7.0"
41
+ },
42
+ "devDependencies": {
43
+ "@tailwindcss/vite": "^4.1.18",
44
+ "@typescript-eslint/eslint-plugin": "^8.53.0",
45
+ "@typescript-eslint/parser": "^8.53.0",
46
+ "@vitejs/plugin-vue": "^6.0.3",
47
+ "eslint": "^9.39.2",
48
+ "eslint-plugin-vue": "^10.6.2",
49
+ "globals": "^17.0.0",
50
+ "tailwindcss": "^4.1.18",
51
+ "typescript": "~5.9.3",
52
+ "vite": "^7.3.1",
53
+ "vue": "^3.5.26",
54
+ "vue-eslint-parser": "^10.2.0",
55
+ "vue-tsc": "^3.2.2"
56
+ },
57
+ "keywords": ["guichat", "plugin", "music", "musicxml", "sheet-music"],
58
+ "license": "MIT"
59
+ }