@marsbdigital/paperclip-content-sprint-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.
- package/README.md +47 -0
- package/dist/index.js +6906 -0
- package/dist/index.js.map +7 -0
- package/dist/manifest.js +74 -0
- package/dist/manifest.js.map +7 -0
- package/dist/ui/index.js +344 -0
- package/dist/ui/index.js.map +7 -0
- package/package.json +42 -0
- package/plugin.json +65 -0
package/dist/manifest.js
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
// plugin.json
|
|
2
|
+
var plugin_default = {
|
|
3
|
+
id: "marsbdigital.paperclip-content-sprint-plugin",
|
|
4
|
+
apiVersion: 1,
|
|
5
|
+
version: "0.1.0",
|
|
6
|
+
displayName: "Content Sprint AI",
|
|
7
|
+
description: "Generate five structured social posts (authority, engagement, conversion) from product context for LinkedIn or X.",
|
|
8
|
+
author: "Mars B Digital",
|
|
9
|
+
categories: ["automation", "ui"],
|
|
10
|
+
minimumHostVersion: "2026.318.0",
|
|
11
|
+
capabilities: [
|
|
12
|
+
"agent.tools.register",
|
|
13
|
+
"jobs.schedule",
|
|
14
|
+
"ui.action.register",
|
|
15
|
+
"ui.dashboardWidget.register"
|
|
16
|
+
],
|
|
17
|
+
entrypoints: {
|
|
18
|
+
worker: "dist/index.js",
|
|
19
|
+
ui: "dist/ui"
|
|
20
|
+
},
|
|
21
|
+
tools: [
|
|
22
|
+
{
|
|
23
|
+
name: "generate_content_batch",
|
|
24
|
+
displayName: "Generate content batch",
|
|
25
|
+
description: "Creates five social posts (2 authority, 2 engagement, 1 conversion) from product name, description, audience, and platform.",
|
|
26
|
+
parametersSchema: {
|
|
27
|
+
type: "object",
|
|
28
|
+
properties: {
|
|
29
|
+
productName: { type: "string", description: "Product or offer name" },
|
|
30
|
+
productDescription: { type: "string", description: "What the product does and why it matters" },
|
|
31
|
+
targetAudience: { type: "string", description: "Who you are writing for" },
|
|
32
|
+
platform: {
|
|
33
|
+
type: "string",
|
|
34
|
+
enum: ["linkedin", "twitter"],
|
|
35
|
+
description: "Target network"
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
required: ["productName", "productDescription", "targetAudience", "platform"]
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
],
|
|
42
|
+
jobs: [
|
|
43
|
+
{
|
|
44
|
+
jobKey: "run_content_sprint",
|
|
45
|
+
displayName: "Run content sprint",
|
|
46
|
+
description: "Generates a sample batch using placeholder product input (for demos and smoke tests).",
|
|
47
|
+
schedule: "0 9 * * 1"
|
|
48
|
+
}
|
|
49
|
+
],
|
|
50
|
+
ui: {
|
|
51
|
+
slots: [
|
|
52
|
+
{
|
|
53
|
+
type: "globalToolbarButton",
|
|
54
|
+
id: "content-sprint-toolbar",
|
|
55
|
+
displayName: "Content Sprint",
|
|
56
|
+
exportName: "ToolbarButton"
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
type: "dashboardWidget",
|
|
60
|
+
id: "content-sprint-dashboard",
|
|
61
|
+
displayName: "Content Sprint AI",
|
|
62
|
+
exportName: "ContentSprintPanel"
|
|
63
|
+
}
|
|
64
|
+
]
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
// src/manifest.ts
|
|
69
|
+
var manifest = plugin_default;
|
|
70
|
+
var manifest_default = manifest;
|
|
71
|
+
export {
|
|
72
|
+
manifest_default as default
|
|
73
|
+
};
|
|
74
|
+
//# sourceMappingURL=manifest.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../plugin.json", "../src/manifest.ts"],
|
|
4
|
+
"sourcesContent": ["{\n \"id\": \"marsbdigital.paperclip-content-sprint-plugin\",\n \"apiVersion\": 1,\n \"version\": \"0.1.0\",\n \"displayName\": \"Content Sprint AI\",\n \"description\": \"Generate five structured social posts (authority, engagement, conversion) from product context for LinkedIn or X.\",\n \"author\": \"Mars B Digital\",\n \"categories\": [\"automation\", \"ui\"],\n \"minimumHostVersion\": \"2026.318.0\",\n \"capabilities\": [\n \"agent.tools.register\",\n \"jobs.schedule\",\n \"ui.action.register\",\n \"ui.dashboardWidget.register\"\n ],\n \"entrypoints\": {\n \"worker\": \"dist/index.js\",\n \"ui\": \"dist/ui\"\n },\n \"tools\": [\n {\n \"name\": \"generate_content_batch\",\n \"displayName\": \"Generate content batch\",\n \"description\": \"Creates five social posts (2 authority, 2 engagement, 1 conversion) from product name, description, audience, and platform.\",\n \"parametersSchema\": {\n \"type\": \"object\",\n \"properties\": {\n \"productName\": { \"type\": \"string\", \"description\": \"Product or offer name\" },\n \"productDescription\": { \"type\": \"string\", \"description\": \"What the product does and why it matters\" },\n \"targetAudience\": { \"type\": \"string\", \"description\": \"Who you are writing for\" },\n \"platform\": {\n \"type\": \"string\",\n \"enum\": [\"linkedin\", \"twitter\"],\n \"description\": \"Target network\"\n }\n },\n \"required\": [\"productName\", \"productDescription\", \"targetAudience\", \"platform\"]\n }\n }\n ],\n \"jobs\": [\n {\n \"jobKey\": \"run_content_sprint\",\n \"displayName\": \"Run content sprint\",\n \"description\": \"Generates a sample batch using placeholder product input (for demos and smoke tests).\",\n \"schedule\": \"0 9 * * 1\"\n }\n ],\n \"ui\": {\n \"slots\": [\n {\n \"type\": \"globalToolbarButton\",\n \"id\": \"content-sprint-toolbar\",\n \"displayName\": \"Content Sprint\",\n \"exportName\": \"ToolbarButton\"\n },\n {\n \"type\": \"dashboardWidget\",\n \"id\": \"content-sprint-dashboard\",\n \"displayName\": \"Content Sprint AI\",\n \"exportName\": \"ContentSprintPanel\"\n }\n ]\n }\n}\n", "import type { PaperclipPluginManifestV1 } from \"@paperclipai/shared\";\nimport manifestJson from \"../plugin.json\" with { type: \"json\" };\n\nconst manifest = manifestJson as PaperclipPluginManifestV1;\n\nexport default manifest;\n"],
|
|
5
|
+
"mappings": ";AAAA;AAAA,EACE,IAAM;AAAA,EACN,YAAc;AAAA,EACd,SAAW;AAAA,EACX,aAAe;AAAA,EACf,aAAe;AAAA,EACf,QAAU;AAAA,EACV,YAAc,CAAC,cAAc,IAAI;AAAA,EACjC,oBAAsB;AAAA,EACtB,cAAgB;AAAA,IACd;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,aAAe;AAAA,IACb,QAAU;AAAA,IACV,IAAM;AAAA,EACR;AAAA,EACA,OAAS;AAAA,IACP;AAAA,MACE,MAAQ;AAAA,MACR,aAAe;AAAA,MACf,aAAe;AAAA,MACf,kBAAoB;AAAA,QAClB,MAAQ;AAAA,QACR,YAAc;AAAA,UACZ,aAAe,EAAE,MAAQ,UAAU,aAAe,wBAAwB;AAAA,UAC1E,oBAAsB,EAAE,MAAQ,UAAU,aAAe,2CAA2C;AAAA,UACpG,gBAAkB,EAAE,MAAQ,UAAU,aAAe,0BAA0B;AAAA,UAC/E,UAAY;AAAA,YACV,MAAQ;AAAA,YACR,MAAQ,CAAC,YAAY,SAAS;AAAA,YAC9B,aAAe;AAAA,UACjB;AAAA,QACF;AAAA,QACA,UAAY,CAAC,eAAe,sBAAsB,kBAAkB,UAAU;AAAA,MAChF;AAAA,IACF;AAAA,EACF;AAAA,EACA,MAAQ;AAAA,IACN;AAAA,MACE,QAAU;AAAA,MACV,aAAe;AAAA,MACf,aAAe;AAAA,MACf,UAAY;AAAA,IACd;AAAA,EACF;AAAA,EACA,IAAM;AAAA,IACJ,OAAS;AAAA,MACP;AAAA,QACE,MAAQ;AAAA,QACR,IAAM;AAAA,QACN,aAAe;AAAA,QACf,YAAc;AAAA,MAChB;AAAA,MACA;AAAA,QACE,MAAQ;AAAA,QACR,IAAM;AAAA,QACN,aAAe;AAAA,QACf,YAAc;AAAA,MAChB;AAAA,IACF;AAAA,EACF;AACF;;;AC7DA,IAAM,WAAW;AAEjB,IAAO,mBAAQ;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
package/dist/ui/index.js
ADDED
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
// src/ui/ToolbarButton.tsx
|
|
2
|
+
import { useCallback, useState } from "react";
|
|
3
|
+
import { usePluginAction } from "@paperclipai/plugin-sdk/ui";
|
|
4
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
5
|
+
function ToolbarButton({ context }) {
|
|
6
|
+
const runGenerate = usePluginAction("generate_content_sprint");
|
|
7
|
+
const [open, setOpen] = useState(false);
|
|
8
|
+
const [productName, setProductName] = useState("");
|
|
9
|
+
const [productDescription, setProductDescription] = useState("");
|
|
10
|
+
const [targetAudience, setTargetAudience] = useState("");
|
|
11
|
+
const [platform, setPlatform] = useState("linkedin");
|
|
12
|
+
const [loading, setLoading] = useState(false);
|
|
13
|
+
const [error, setError] = useState(null);
|
|
14
|
+
const [result, setResult] = useState(null);
|
|
15
|
+
const onGenerate = useCallback(async () => {
|
|
16
|
+
setLoading(true);
|
|
17
|
+
setError(null);
|
|
18
|
+
setResult(null);
|
|
19
|
+
try {
|
|
20
|
+
const data = await runGenerate({
|
|
21
|
+
companyId: context.companyId,
|
|
22
|
+
productName,
|
|
23
|
+
productDescription,
|
|
24
|
+
targetAudience,
|
|
25
|
+
platform
|
|
26
|
+
});
|
|
27
|
+
setResult(data);
|
|
28
|
+
} catch (e) {
|
|
29
|
+
setError(e instanceof Error ? e.message : "Generation failed");
|
|
30
|
+
} finally {
|
|
31
|
+
setLoading(false);
|
|
32
|
+
}
|
|
33
|
+
}, [runGenerate, context.companyId, productName, productDescription, targetAudience, platform]);
|
|
34
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
35
|
+
/* @__PURE__ */ jsx(
|
|
36
|
+
"button",
|
|
37
|
+
{
|
|
38
|
+
type: "button",
|
|
39
|
+
onClick: () => setOpen(true),
|
|
40
|
+
style: {
|
|
41
|
+
display: "inline-flex",
|
|
42
|
+
alignItems: "center",
|
|
43
|
+
gap: 6,
|
|
44
|
+
padding: "6px 12px",
|
|
45
|
+
borderRadius: 8,
|
|
46
|
+
border: "1px solid rgba(0,0,0,0.12)",
|
|
47
|
+
background: "#fff",
|
|
48
|
+
fontWeight: 600,
|
|
49
|
+
fontSize: "0.85rem",
|
|
50
|
+
cursor: "pointer"
|
|
51
|
+
},
|
|
52
|
+
children: "\u26A1 Content Sprint"
|
|
53
|
+
}
|
|
54
|
+
),
|
|
55
|
+
open ? /* @__PURE__ */ jsx(
|
|
56
|
+
"div",
|
|
57
|
+
{
|
|
58
|
+
role: "dialog",
|
|
59
|
+
"aria-modal": "true",
|
|
60
|
+
"aria-label": "Content Sprint",
|
|
61
|
+
style: {
|
|
62
|
+
position: "fixed",
|
|
63
|
+
inset: 0,
|
|
64
|
+
zIndex: 80,
|
|
65
|
+
display: "flex",
|
|
66
|
+
alignItems: "center",
|
|
67
|
+
justifyContent: "center",
|
|
68
|
+
padding: 16,
|
|
69
|
+
background: "rgba(0,0,0,0.35)"
|
|
70
|
+
},
|
|
71
|
+
onClick: () => !loading && setOpen(false),
|
|
72
|
+
children: /* @__PURE__ */ jsxs(
|
|
73
|
+
"div",
|
|
74
|
+
{
|
|
75
|
+
style: {
|
|
76
|
+
width: "min(560px, 100%)",
|
|
77
|
+
maxHeight: "90vh",
|
|
78
|
+
overflow: "auto",
|
|
79
|
+
padding: 20,
|
|
80
|
+
borderRadius: 14,
|
|
81
|
+
background: "#fff",
|
|
82
|
+
boxShadow: "0 20px 50px rgba(0,0,0,0.2)",
|
|
83
|
+
fontFamily: "system-ui, sans-serif"
|
|
84
|
+
},
|
|
85
|
+
onClick: (e) => e.stopPropagation(),
|
|
86
|
+
children: [
|
|
87
|
+
/* @__PURE__ */ jsxs("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: 14 }, children: [
|
|
88
|
+
/* @__PURE__ */ jsx("h2", { style: { margin: 0, fontSize: "1.1rem" }, children: "Content Sprint" }),
|
|
89
|
+
/* @__PURE__ */ jsx(
|
|
90
|
+
"button",
|
|
91
|
+
{
|
|
92
|
+
type: "button",
|
|
93
|
+
onClick: () => setOpen(false),
|
|
94
|
+
disabled: loading,
|
|
95
|
+
style: { border: "none", background: "transparent", cursor: "pointer", fontSize: "1.2rem" },
|
|
96
|
+
"aria-label": "Close",
|
|
97
|
+
children: "\xD7"
|
|
98
|
+
}
|
|
99
|
+
)
|
|
100
|
+
] }),
|
|
101
|
+
/* @__PURE__ */ jsxs("div", { style: { display: "grid", gap: 10, marginBottom: 12 }, children: [
|
|
102
|
+
/* @__PURE__ */ jsx(
|
|
103
|
+
"input",
|
|
104
|
+
{
|
|
105
|
+
placeholder: "Product name",
|
|
106
|
+
value: productName,
|
|
107
|
+
onChange: (e) => setProductName(e.target.value),
|
|
108
|
+
style: field
|
|
109
|
+
}
|
|
110
|
+
),
|
|
111
|
+
/* @__PURE__ */ jsx(
|
|
112
|
+
"textarea",
|
|
113
|
+
{
|
|
114
|
+
placeholder: "Product description",
|
|
115
|
+
value: productDescription,
|
|
116
|
+
onChange: (e) => setProductDescription(e.target.value),
|
|
117
|
+
style: { ...field, minHeight: 72 }
|
|
118
|
+
}
|
|
119
|
+
),
|
|
120
|
+
/* @__PURE__ */ jsx(
|
|
121
|
+
"input",
|
|
122
|
+
{
|
|
123
|
+
placeholder: "Target audience",
|
|
124
|
+
value: targetAudience,
|
|
125
|
+
onChange: (e) => setTargetAudience(e.target.value),
|
|
126
|
+
style: field
|
|
127
|
+
}
|
|
128
|
+
),
|
|
129
|
+
/* @__PURE__ */ jsxs(
|
|
130
|
+
"select",
|
|
131
|
+
{
|
|
132
|
+
value: platform,
|
|
133
|
+
onChange: (e) => setPlatform(e.target.value),
|
|
134
|
+
style: field,
|
|
135
|
+
children: [
|
|
136
|
+
/* @__PURE__ */ jsx("option", { value: "linkedin", children: "LinkedIn" }),
|
|
137
|
+
/* @__PURE__ */ jsx("option", { value: "twitter", children: "X (Twitter)" })
|
|
138
|
+
]
|
|
139
|
+
}
|
|
140
|
+
)
|
|
141
|
+
] }),
|
|
142
|
+
/* @__PURE__ */ jsx(
|
|
143
|
+
"button",
|
|
144
|
+
{
|
|
145
|
+
type: "button",
|
|
146
|
+
onClick: () => void onGenerate(),
|
|
147
|
+
disabled: loading,
|
|
148
|
+
style: {
|
|
149
|
+
width: "100%",
|
|
150
|
+
padding: "10px",
|
|
151
|
+
borderRadius: 8,
|
|
152
|
+
border: "none",
|
|
153
|
+
fontWeight: 600,
|
|
154
|
+
background: loading ? "#999" : "#111",
|
|
155
|
+
color: "#fff",
|
|
156
|
+
cursor: loading ? "wait" : "pointer",
|
|
157
|
+
marginBottom: 12
|
|
158
|
+
},
|
|
159
|
+
children: loading ? "Generating\u2026" : "Generate 5 posts"
|
|
160
|
+
}
|
|
161
|
+
),
|
|
162
|
+
error ? /* @__PURE__ */ jsx("p", { style: { color: "#b00020", fontSize: "0.85rem" }, role: "alert", children: error }) : null,
|
|
163
|
+
result?.posts?.length ? /* @__PURE__ */ jsx("ol", { style: { margin: 0, paddingLeft: 18, fontSize: "0.82rem", lineHeight: 1.4 }, children: result.posts.map((p, i) => /* @__PURE__ */ jsxs("li", { style: { marginBottom: 10 }, children: [
|
|
164
|
+
/* @__PURE__ */ jsx("strong", { children: p.type }),
|
|
165
|
+
" \u2014 ",
|
|
166
|
+
p.hook
|
|
167
|
+
] }, i)) }) : null
|
|
168
|
+
]
|
|
169
|
+
}
|
|
170
|
+
)
|
|
171
|
+
}
|
|
172
|
+
) : null
|
|
173
|
+
] });
|
|
174
|
+
}
|
|
175
|
+
var field = {
|
|
176
|
+
padding: "8px 10px",
|
|
177
|
+
borderRadius: 8,
|
|
178
|
+
border: "1px solid #ccc",
|
|
179
|
+
fontSize: "0.88rem"
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
// src/ui/ContentSprintPanel.tsx
|
|
183
|
+
import { useCallback as useCallback2, useState as useState2 } from "react";
|
|
184
|
+
import { usePluginAction as usePluginAction2 } from "@paperclipai/plugin-sdk/ui";
|
|
185
|
+
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
186
|
+
function ContentSprintPanel({ context }) {
|
|
187
|
+
const runGenerate = usePluginAction2("generate_content_sprint");
|
|
188
|
+
const [productName, setProductName] = useState2("");
|
|
189
|
+
const [productDescription, setProductDescription] = useState2("");
|
|
190
|
+
const [targetAudience, setTargetAudience] = useState2("");
|
|
191
|
+
const [platform, setPlatform] = useState2("linkedin");
|
|
192
|
+
const [loading, setLoading] = useState2(false);
|
|
193
|
+
const [error, setError] = useState2(null);
|
|
194
|
+
const [result, setResult] = useState2(null);
|
|
195
|
+
const onGenerate = useCallback2(async () => {
|
|
196
|
+
setLoading(true);
|
|
197
|
+
setError(null);
|
|
198
|
+
setResult(null);
|
|
199
|
+
try {
|
|
200
|
+
const data = await runGenerate({
|
|
201
|
+
companyId: context.companyId,
|
|
202
|
+
productName,
|
|
203
|
+
productDescription,
|
|
204
|
+
targetAudience,
|
|
205
|
+
platform
|
|
206
|
+
});
|
|
207
|
+
setResult(data);
|
|
208
|
+
} catch (e) {
|
|
209
|
+
setError(e instanceof Error ? e.message : "Generation failed");
|
|
210
|
+
} finally {
|
|
211
|
+
setLoading(false);
|
|
212
|
+
}
|
|
213
|
+
}, [runGenerate, context.companyId, productName, productDescription, targetAudience, platform]);
|
|
214
|
+
return /* @__PURE__ */ jsxs2(
|
|
215
|
+
"section",
|
|
216
|
+
{
|
|
217
|
+
style: {
|
|
218
|
+
display: "grid",
|
|
219
|
+
gap: 16,
|
|
220
|
+
padding: 16,
|
|
221
|
+
borderRadius: 12,
|
|
222
|
+
border: "1px solid rgba(0,0,0,0.08)",
|
|
223
|
+
background: "linear-gradient(165deg, #fafafa 0%, #fff 45%)",
|
|
224
|
+
fontFamily: "system-ui, sans-serif",
|
|
225
|
+
maxWidth: 720
|
|
226
|
+
},
|
|
227
|
+
children: [
|
|
228
|
+
/* @__PURE__ */ jsxs2("header", { children: [
|
|
229
|
+
/* @__PURE__ */ jsx2("h2", { style: { margin: 0, fontSize: "1.15rem", fontWeight: 650 }, children: "Content Sprint AI" }),
|
|
230
|
+
/* @__PURE__ */ jsx2("p", { style: { margin: "6px 0 0", fontSize: "0.875rem", color: "#444" }, children: "Five posts: two authority, two engagement, one conversion." })
|
|
231
|
+
] }),
|
|
232
|
+
/* @__PURE__ */ jsxs2("div", { style: { display: "grid", gap: 10 }, children: [
|
|
233
|
+
/* @__PURE__ */ jsxs2("label", { style: { display: "grid", gap: 4, fontSize: "0.8rem" }, children: [
|
|
234
|
+
/* @__PURE__ */ jsx2("span", { style: { fontWeight: 600 }, children: "Product name" }),
|
|
235
|
+
/* @__PURE__ */ jsx2(
|
|
236
|
+
"input",
|
|
237
|
+
{
|
|
238
|
+
value: productName,
|
|
239
|
+
onChange: (e) => setProductName(e.target.value),
|
|
240
|
+
style: inputStyle,
|
|
241
|
+
placeholder: "e.g. Northwind CRM"
|
|
242
|
+
}
|
|
243
|
+
)
|
|
244
|
+
] }),
|
|
245
|
+
/* @__PURE__ */ jsxs2("label", { style: { display: "grid", gap: 4, fontSize: "0.8rem" }, children: [
|
|
246
|
+
/* @__PURE__ */ jsx2("span", { style: { fontWeight: 600 }, children: "Product description" }),
|
|
247
|
+
/* @__PURE__ */ jsx2(
|
|
248
|
+
"textarea",
|
|
249
|
+
{
|
|
250
|
+
value: productDescription,
|
|
251
|
+
onChange: (e) => setProductDescription(e.target.value),
|
|
252
|
+
style: { ...inputStyle, minHeight: 88, resize: "vertical" },
|
|
253
|
+
placeholder: "What it does and the outcome for customers"
|
|
254
|
+
}
|
|
255
|
+
)
|
|
256
|
+
] }),
|
|
257
|
+
/* @__PURE__ */ jsxs2("label", { style: { display: "grid", gap: 4, fontSize: "0.8rem" }, children: [
|
|
258
|
+
/* @__PURE__ */ jsx2("span", { style: { fontWeight: 600 }, children: "Target audience" }),
|
|
259
|
+
/* @__PURE__ */ jsx2(
|
|
260
|
+
"input",
|
|
261
|
+
{
|
|
262
|
+
value: targetAudience,
|
|
263
|
+
onChange: (e) => setTargetAudience(e.target.value),
|
|
264
|
+
style: inputStyle,
|
|
265
|
+
placeholder: "e.g. Heads of ops at mid-market manufacturers"
|
|
266
|
+
}
|
|
267
|
+
)
|
|
268
|
+
] }),
|
|
269
|
+
/* @__PURE__ */ jsxs2("label", { style: { display: "grid", gap: 4, fontSize: "0.8rem" }, children: [
|
|
270
|
+
/* @__PURE__ */ jsx2("span", { style: { fontWeight: 600 }, children: "Platform" }),
|
|
271
|
+
/* @__PURE__ */ jsxs2(
|
|
272
|
+
"select",
|
|
273
|
+
{
|
|
274
|
+
value: platform,
|
|
275
|
+
onChange: (e) => setPlatform(e.target.value),
|
|
276
|
+
style: inputStyle,
|
|
277
|
+
children: [
|
|
278
|
+
/* @__PURE__ */ jsx2("option", { value: "linkedin", children: "LinkedIn" }),
|
|
279
|
+
/* @__PURE__ */ jsx2("option", { value: "twitter", children: "X (Twitter)" })
|
|
280
|
+
]
|
|
281
|
+
}
|
|
282
|
+
)
|
|
283
|
+
] })
|
|
284
|
+
] }),
|
|
285
|
+
/* @__PURE__ */ jsxs2("div", { style: { display: "flex", gap: 10, alignItems: "center" }, children: [
|
|
286
|
+
/* @__PURE__ */ jsx2(
|
|
287
|
+
"button",
|
|
288
|
+
{
|
|
289
|
+
type: "button",
|
|
290
|
+
onClick: () => void onGenerate(),
|
|
291
|
+
disabled: loading,
|
|
292
|
+
style: {
|
|
293
|
+
padding: "10px 18px",
|
|
294
|
+
borderRadius: 8,
|
|
295
|
+
border: "none",
|
|
296
|
+
fontWeight: 600,
|
|
297
|
+
cursor: loading ? "wait" : "pointer",
|
|
298
|
+
background: loading ? "#bbb" : "#111",
|
|
299
|
+
color: "#fff"
|
|
300
|
+
},
|
|
301
|
+
children: loading ? "Generating\u2026" : "Generate 5 posts"
|
|
302
|
+
}
|
|
303
|
+
),
|
|
304
|
+
context.companyId == null ? /* @__PURE__ */ jsx2("span", { style: { fontSize: "0.8rem", color: "#a40" }, children: "Select a company to run actions." }) : null
|
|
305
|
+
] }),
|
|
306
|
+
error ? /* @__PURE__ */ jsx2("p", { style: { margin: 0, color: "#b00020", fontSize: "0.875rem" }, role: "alert", children: error }) : null,
|
|
307
|
+
result?.posts?.length ? /* @__PURE__ */ jsx2("ul", { style: { margin: 0, padding: 0, listStyle: "none", display: "grid", gap: 14 }, children: result.posts.map((post, i) => /* @__PURE__ */ jsxs2(
|
|
308
|
+
"li",
|
|
309
|
+
{
|
|
310
|
+
style: {
|
|
311
|
+
padding: 12,
|
|
312
|
+
borderRadius: 10,
|
|
313
|
+
background: "#fff",
|
|
314
|
+
border: "1px solid rgba(0,0,0,0.06)"
|
|
315
|
+
},
|
|
316
|
+
children: [
|
|
317
|
+
/* @__PURE__ */ jsx2("div", { style: { fontSize: "0.72rem", textTransform: "uppercase", letterSpacing: "0.04em", color: "#666" }, children: post.type }),
|
|
318
|
+
/* @__PURE__ */ jsx2("p", { style: { margin: "6px 0", fontWeight: 650 }, children: post.hook }),
|
|
319
|
+
/* @__PURE__ */ jsx2("p", { style: { margin: "0 0 8px", whiteSpace: "pre-wrap", fontSize: "0.9rem", lineHeight: 1.45 }, children: post.body }),
|
|
320
|
+
/* @__PURE__ */ jsxs2("p", { style: { margin: 0, fontSize: "0.85rem", color: "#333" }, children: [
|
|
321
|
+
/* @__PURE__ */ jsx2("strong", { children: "CTA:" }),
|
|
322
|
+
" ",
|
|
323
|
+
post.cta
|
|
324
|
+
] }),
|
|
325
|
+
post.hashtags?.length ? /* @__PURE__ */ jsx2("p", { style: { margin: "8px 0 0", fontSize: "0.8rem", color: "#555" }, children: post.hashtags.map((h) => `#${h}`).join(" ") }) : null
|
|
326
|
+
]
|
|
327
|
+
},
|
|
328
|
+
i
|
|
329
|
+
)) }) : null
|
|
330
|
+
]
|
|
331
|
+
}
|
|
332
|
+
);
|
|
333
|
+
}
|
|
334
|
+
var inputStyle = {
|
|
335
|
+
padding: "8px 10px",
|
|
336
|
+
borderRadius: 8,
|
|
337
|
+
border: "1px solid #ccc",
|
|
338
|
+
fontSize: "0.9rem"
|
|
339
|
+
};
|
|
340
|
+
export {
|
|
341
|
+
ContentSprintPanel,
|
|
342
|
+
ToolbarButton
|
|
343
|
+
};
|
|
344
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/ui/ToolbarButton.tsx", "../../src/ui/ContentSprintPanel.tsx"],
|
|
4
|
+
"sourcesContent": ["import { useCallback, useState, type CSSProperties } from \"react\";\nimport { usePluginAction, type PluginWidgetProps } from \"@paperclipai/plugin-sdk/ui\";\nimport type { ContentBatchResult } from \"../contentTypes.js\";\n\n/**\n * Global toolbar entry \u2014 opens a compact sprint panel in a host-style overlay.\n */\nexport function ToolbarButton({ context }: PluginWidgetProps) {\n const runGenerate = usePluginAction(\"generate_content_sprint\");\n const [open, setOpen] = useState(false);\n const [productName, setProductName] = useState(\"\");\n const [productDescription, setProductDescription] = useState(\"\");\n const [targetAudience, setTargetAudience] = useState(\"\");\n const [platform, setPlatform] = useState<\"linkedin\" | \"twitter\">(\"linkedin\");\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [result, setResult] = useState<ContentBatchResult | null>(null);\n\n const onGenerate = useCallback(async () => {\n setLoading(true);\n setError(null);\n setResult(null);\n try {\n const data = (await runGenerate({\n companyId: context.companyId,\n productName,\n productDescription,\n targetAudience,\n platform,\n })) as ContentBatchResult;\n setResult(data);\n } catch (e) {\n setError(e instanceof Error ? e.message : \"Generation failed\");\n } finally {\n setLoading(false);\n }\n }, [runGenerate, context.companyId, productName, productDescription, targetAudience, platform]);\n\n return (\n <>\n <button\n type=\"button\"\n onClick={() => setOpen(true)}\n style={{\n display: \"inline-flex\",\n alignItems: \"center\",\n gap: 6,\n padding: \"6px 12px\",\n borderRadius: 8,\n border: \"1px solid rgba(0,0,0,0.12)\",\n background: \"#fff\",\n fontWeight: 600,\n fontSize: \"0.85rem\",\n cursor: \"pointer\",\n }}\n >\n \u26A1 Content Sprint\n </button>\n\n {open ? (\n <div\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label=\"Content Sprint\"\n style={{\n position: \"fixed\",\n inset: 0,\n zIndex: 80,\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n padding: 16,\n background: \"rgba(0,0,0,0.35)\",\n }}\n onClick={() => !loading && setOpen(false)}\n >\n <div\n style={{\n width: \"min(560px, 100%)\",\n maxHeight: \"90vh\",\n overflow: \"auto\",\n padding: 20,\n borderRadius: 14,\n background: \"#fff\",\n boxShadow: \"0 20px 50px rgba(0,0,0,0.2)\",\n fontFamily: \"system-ui, sans-serif\",\n }}\n onClick={(e) => e.stopPropagation()}\n >\n <div style={{ display: \"flex\", justifyContent: \"space-between\", alignItems: \"center\", marginBottom: 14 }}>\n <h2 style={{ margin: 0, fontSize: \"1.1rem\" }}>Content Sprint</h2>\n <button\n type=\"button\"\n onClick={() => setOpen(false)}\n disabled={loading}\n style={{ border: \"none\", background: \"transparent\", cursor: \"pointer\", fontSize: \"1.2rem\" }}\n aria-label=\"Close\"\n >\n \u00D7\n </button>\n </div>\n\n <div style={{ display: \"grid\", gap: 10, marginBottom: 12 }}>\n <input\n placeholder=\"Product name\"\n value={productName}\n onChange={(e) => setProductName(e.target.value)}\n style={field}\n />\n <textarea\n placeholder=\"Product description\"\n value={productDescription}\n onChange={(e) => setProductDescription(e.target.value)}\n style={{ ...field, minHeight: 72 }}\n />\n <input\n placeholder=\"Target audience\"\n value={targetAudience}\n onChange={(e) => setTargetAudience(e.target.value)}\n style={field}\n />\n <select\n value={platform}\n onChange={(e) => setPlatform(e.target.value as \"linkedin\" | \"twitter\")}\n style={field}\n >\n <option value=\"linkedin\">LinkedIn</option>\n <option value=\"twitter\">X (Twitter)</option>\n </select>\n </div>\n\n <button\n type=\"button\"\n onClick={() => void onGenerate()}\n disabled={loading}\n style={{\n width: \"100%\",\n padding: \"10px\",\n borderRadius: 8,\n border: \"none\",\n fontWeight: 600,\n background: loading ? \"#999\" : \"#111\",\n color: \"#fff\",\n cursor: loading ? \"wait\" : \"pointer\",\n marginBottom: 12,\n }}\n >\n {loading ? \"Generating\u2026\" : \"Generate 5 posts\"}\n </button>\n\n {error ? (\n <p style={{ color: \"#b00020\", fontSize: \"0.85rem\" }} role=\"alert\">\n {error}\n </p>\n ) : null}\n\n {result?.posts?.length ? (\n <ol style={{ margin: 0, paddingLeft: 18, fontSize: \"0.82rem\", lineHeight: 1.4 }}>\n {result.posts.map((p, i) => (\n <li key={i} style={{ marginBottom: 10 }}>\n <strong>{p.type}</strong> \u2014 {p.hook}\n </li>\n ))}\n </ol>\n ) : null}\n </div>\n </div>\n ) : null}\n </>\n );\n}\n\nconst field: CSSProperties = {\n padding: \"8px 10px\",\n borderRadius: 8,\n border: \"1px solid #ccc\",\n fontSize: \"0.88rem\",\n};\n", "import { useCallback, useState, type CSSProperties } from \"react\";\nimport { usePluginAction, type PluginWidgetProps } from \"@paperclipai/plugin-sdk/ui\";\nimport type { ContentBatchResult } from \"../contentTypes.js\";\n\nexport function ContentSprintPanel({ context }: PluginWidgetProps) {\n const runGenerate = usePluginAction(\"generate_content_sprint\");\n const [productName, setProductName] = useState(\"\");\n const [productDescription, setProductDescription] = useState(\"\");\n const [targetAudience, setTargetAudience] = useState(\"\");\n const [platform, setPlatform] = useState<\"linkedin\" | \"twitter\">(\"linkedin\");\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [result, setResult] = useState<ContentBatchResult | null>(null);\n\n const onGenerate = useCallback(async () => {\n setLoading(true);\n setError(null);\n setResult(null);\n try {\n const data = (await runGenerate({\n companyId: context.companyId,\n productName,\n productDescription,\n targetAudience,\n platform,\n })) as ContentBatchResult;\n setResult(data);\n } catch (e) {\n setError(e instanceof Error ? e.message : \"Generation failed\");\n } finally {\n setLoading(false);\n }\n }, [runGenerate, context.companyId, productName, productDescription, targetAudience, platform]);\n\n return (\n <section\n style={{\n display: \"grid\",\n gap: 16,\n padding: 16,\n borderRadius: 12,\n border: \"1px solid rgba(0,0,0,0.08)\",\n background: \"linear-gradient(165deg, #fafafa 0%, #fff 45%)\",\n fontFamily: \"system-ui, sans-serif\",\n maxWidth: 720,\n }}\n >\n <header>\n <h2 style={{ margin: 0, fontSize: \"1.15rem\", fontWeight: 650 }}>Content Sprint AI</h2>\n <p style={{ margin: \"6px 0 0\", fontSize: \"0.875rem\", color: \"#444\" }}>\n Five posts: two authority, two engagement, one conversion.\n </p>\n </header>\n\n <div style={{ display: \"grid\", gap: 10 }}>\n <label style={{ display: \"grid\", gap: 4, fontSize: \"0.8rem\" }}>\n <span style={{ fontWeight: 600 }}>Product name</span>\n <input\n value={productName}\n onChange={(e) => setProductName(e.target.value)}\n style={inputStyle}\n placeholder=\"e.g. Northwind CRM\"\n />\n </label>\n <label style={{ display: \"grid\", gap: 4, fontSize: \"0.8rem\" }}>\n <span style={{ fontWeight: 600 }}>Product description</span>\n <textarea\n value={productDescription}\n onChange={(e) => setProductDescription(e.target.value)}\n style={{ ...inputStyle, minHeight: 88, resize: \"vertical\" }}\n placeholder=\"What it does and the outcome for customers\"\n />\n </label>\n <label style={{ display: \"grid\", gap: 4, fontSize: \"0.8rem\" }}>\n <span style={{ fontWeight: 600 }}>Target audience</span>\n <input\n value={targetAudience}\n onChange={(e) => setTargetAudience(e.target.value)}\n style={inputStyle}\n placeholder=\"e.g. Heads of ops at mid-market manufacturers\"\n />\n </label>\n <label style={{ display: \"grid\", gap: 4, fontSize: \"0.8rem\" }}>\n <span style={{ fontWeight: 600 }}>Platform</span>\n <select\n value={platform}\n onChange={(e) => setPlatform(e.target.value as \"linkedin\" | \"twitter\")}\n style={inputStyle}\n >\n <option value=\"linkedin\">LinkedIn</option>\n <option value=\"twitter\">X (Twitter)</option>\n </select>\n </label>\n </div>\n\n <div style={{ display: \"flex\", gap: 10, alignItems: \"center\" }}>\n <button\n type=\"button\"\n onClick={() => void onGenerate()}\n disabled={loading}\n style={{\n padding: \"10px 18px\",\n borderRadius: 8,\n border: \"none\",\n fontWeight: 600,\n cursor: loading ? \"wait\" : \"pointer\",\n background: loading ? \"#bbb\" : \"#111\",\n color: \"#fff\",\n }}\n >\n {loading ? \"Generating\u2026\" : \"Generate 5 posts\"}\n </button>\n {context.companyId == null ? (\n <span style={{ fontSize: \"0.8rem\", color: \"#a40\" }}>Select a company to run actions.</span>\n ) : null}\n </div>\n\n {error ? (\n <p style={{ margin: 0, color: \"#b00020\", fontSize: \"0.875rem\" }} role=\"alert\">\n {error}\n </p>\n ) : null}\n\n {result?.posts?.length ? (\n <ul style={{ margin: 0, padding: 0, listStyle: \"none\", display: \"grid\", gap: 14 }}>\n {result.posts.map((post, i) => (\n <li\n key={i}\n style={{\n padding: 12,\n borderRadius: 10,\n background: \"#fff\",\n border: \"1px solid rgba(0,0,0,0.06)\",\n }}\n >\n <div style={{ fontSize: \"0.72rem\", textTransform: \"uppercase\", letterSpacing: \"0.04em\", color: \"#666\" }}>\n {post.type}\n </div>\n <p style={{ margin: \"6px 0\", fontWeight: 650 }}>{post.hook}</p>\n <p style={{ margin: \"0 0 8px\", whiteSpace: \"pre-wrap\", fontSize: \"0.9rem\", lineHeight: 1.45 }}>\n {post.body}\n </p>\n <p style={{ margin: 0, fontSize: \"0.85rem\", color: \"#333\" }}>\n <strong>CTA:</strong> {post.cta}\n </p>\n {post.hashtags?.length ? (\n <p style={{ margin: \"8px 0 0\", fontSize: \"0.8rem\", color: \"#555\" }}>\n {post.hashtags.map((h) => `#${h}`).join(\" \")}\n </p>\n ) : null}\n </li>\n ))}\n </ul>\n ) : null}\n </section>\n );\n}\n\nconst inputStyle: CSSProperties = {\n padding: \"8px 10px\",\n borderRadius: 8,\n border: \"1px solid #ccc\",\n fontSize: \"0.9rem\",\n};\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["useCallback", "useState", "usePluginAction", "jsx", "jsxs"]
|
|
7
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@marsbdigital/paperclip-content-sprint-plugin",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Content Sprint AI — generate a batch of social posts from product context for Paperclip.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"files": [
|
|
8
|
+
"dist",
|
|
9
|
+
"plugin.json",
|
|
10
|
+
"README.md"
|
|
11
|
+
],
|
|
12
|
+
"scripts": {
|
|
13
|
+
"build": "node scripts/build.mjs",
|
|
14
|
+
"typecheck": "tsc --noEmit"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"paperclip",
|
|
18
|
+
"paperclip-plugin",
|
|
19
|
+
"content",
|
|
20
|
+
"social"
|
|
21
|
+
],
|
|
22
|
+
"author": "Mars B Digital",
|
|
23
|
+
"license": "MIT",
|
|
24
|
+
"peerDependencies": {
|
|
25
|
+
"react": "^18.0.0 || ^19.0.0"
|
|
26
|
+
},
|
|
27
|
+
"dependencies": {
|
|
28
|
+
"zod": "^3.24.0"
|
|
29
|
+
},
|
|
30
|
+
"devDependencies": {
|
|
31
|
+
"@paperclipai/plugin-sdk": "^2026.318.0",
|
|
32
|
+
"@paperclipai/shared": "^2026.318.0",
|
|
33
|
+
"@types/react": "^19.0.0",
|
|
34
|
+
"esbuild": "^0.25.0",
|
|
35
|
+
"react": "^19.0.0",
|
|
36
|
+
"typescript": "^5.7.0"
|
|
37
|
+
},
|
|
38
|
+
"paperclipPlugin": {
|
|
39
|
+
"manifest": "./dist/manifest.js",
|
|
40
|
+
"worker": "./dist/index.js"
|
|
41
|
+
}
|
|
42
|
+
}
|
package/plugin.json
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "marsbdigital.paperclip-content-sprint-plugin",
|
|
3
|
+
"apiVersion": 1,
|
|
4
|
+
"version": "0.1.0",
|
|
5
|
+
"displayName": "Content Sprint AI",
|
|
6
|
+
"description": "Generate five structured social posts (authority, engagement, conversion) from product context for LinkedIn or X.",
|
|
7
|
+
"author": "Mars B Digital",
|
|
8
|
+
"categories": ["automation", "ui"],
|
|
9
|
+
"minimumHostVersion": "2026.318.0",
|
|
10
|
+
"capabilities": [
|
|
11
|
+
"agent.tools.register",
|
|
12
|
+
"jobs.schedule",
|
|
13
|
+
"ui.action.register",
|
|
14
|
+
"ui.dashboardWidget.register"
|
|
15
|
+
],
|
|
16
|
+
"entrypoints": {
|
|
17
|
+
"worker": "dist/index.js",
|
|
18
|
+
"ui": "dist/ui"
|
|
19
|
+
},
|
|
20
|
+
"tools": [
|
|
21
|
+
{
|
|
22
|
+
"name": "generate_content_batch",
|
|
23
|
+
"displayName": "Generate content batch",
|
|
24
|
+
"description": "Creates five social posts (2 authority, 2 engagement, 1 conversion) from product name, description, audience, and platform.",
|
|
25
|
+
"parametersSchema": {
|
|
26
|
+
"type": "object",
|
|
27
|
+
"properties": {
|
|
28
|
+
"productName": { "type": "string", "description": "Product or offer name" },
|
|
29
|
+
"productDescription": { "type": "string", "description": "What the product does and why it matters" },
|
|
30
|
+
"targetAudience": { "type": "string", "description": "Who you are writing for" },
|
|
31
|
+
"platform": {
|
|
32
|
+
"type": "string",
|
|
33
|
+
"enum": ["linkedin", "twitter"],
|
|
34
|
+
"description": "Target network"
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
"required": ["productName", "productDescription", "targetAudience", "platform"]
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
],
|
|
41
|
+
"jobs": [
|
|
42
|
+
{
|
|
43
|
+
"jobKey": "run_content_sprint",
|
|
44
|
+
"displayName": "Run content sprint",
|
|
45
|
+
"description": "Generates a sample batch using placeholder product input (for demos and smoke tests).",
|
|
46
|
+
"schedule": "0 9 * * 1"
|
|
47
|
+
}
|
|
48
|
+
],
|
|
49
|
+
"ui": {
|
|
50
|
+
"slots": [
|
|
51
|
+
{
|
|
52
|
+
"type": "globalToolbarButton",
|
|
53
|
+
"id": "content-sprint-toolbar",
|
|
54
|
+
"displayName": "Content Sprint",
|
|
55
|
+
"exportName": "ToolbarButton"
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
"type": "dashboardWidget",
|
|
59
|
+
"id": "content-sprint-dashboard",
|
|
60
|
+
"displayName": "Content Sprint AI",
|
|
61
|
+
"exportName": "ContentSprintPanel"
|
|
62
|
+
}
|
|
63
|
+
]
|
|
64
|
+
}
|
|
65
|
+
}
|