@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.
@@ -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
+ }
@@ -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
+ }