@kujolang/paperclip 0.1.3 → 0.1.5

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/CHANGELOG.md CHANGED
@@ -1,5 +1,15 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.1.5 - 2026-09-02
4
+
5
+ - Replace the temporary lettermark in the Paperclip workspace with the official adaptive Kujo SVG from kujolang.ai.
6
+
7
+ ## 0.1.4 - 2026-09-02
8
+
9
+ - Show Kujo automatically in Paperclip's current issue view while keeping the shared detail tab for project, issue, and run pages.
10
+ - Replace the basic action list with a polished monochrome workspace, clearer action cards, stronger artifact states, and responsive controls.
11
+ - Correct the empty Context Pack state so it reports that a pack has not been generated.
12
+
3
13
  ## 0.1.3 - 2026-09-02
4
14
 
5
15
  - Resolve the installed `@kujolang/kujo-runtime` package at worker runtime instead of inlining its package resolver into the ESM worker bundle.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Kujo for Paperclip
2
2
 
3
- [![Version](https://img.shields.io/badge/version-0.1.3-black)](https://github.com/kujolang/paperclip/releases/tag/v0.1.3)
3
+ [![Version](https://img.shields.io/badge/version-0.1.5-black)](https://github.com/kujolang/paperclip/releases/tag/v0.1.5)
4
4
  [![License](https://img.shields.io/badge/license-MIT-lightgrey)](LICENSE)
5
5
  [![built with Kujo](https://img.shields.io/badge/built%20with-Kujo-white.svg)](https://github.com/kujolang/kujo)
6
6
 
@@ -14,7 +14,7 @@ You need Paperclip `2026.824.1` or later and Node.js `24.11.0` or later.
14
14
  npx paperclipai plugin install @kujolang/paperclip
15
15
  ```
16
16
 
17
- Restart Paperclip if it is already running. Open a project, issue, or run and select the **Kujo** tab. The status panel should report that the runtime and all four bundled components are ready.
17
+ Restart Paperclip if it is already running. Kujo appears automatically inside Paperclip's current task view. On project and run pages, open the **Kujo** tab. You do not need to switch to the Classic Task Interface.
18
18
 
19
19
  The npm package includes the correct Kujo runtime for macOS arm64/x64, Linux arm64/x64, and Windows x64. Installation does not run `preinstall`, `install`, or `postinstall` scripts.
20
20
 
@@ -22,7 +22,7 @@ See [Installation](docs/INSTALLATION.md) for upgrades, local development install
22
22
 
23
23
  ## Use
24
24
 
25
- Open the **Kujo** tab on a project or issue to:
25
+ Open an issue to use the inline Kujo workspace, or open the **Kujo** tab on a project, issue detail page, or run to:
26
26
 
27
27
  - generate a **Review Pack** for the working tree;
28
28
  - create a task-specific **Context Pack**;
package/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.3
1
+ 0.1.5
package/dist/manifest.js CHANGED
@@ -14527,7 +14527,7 @@ var DEFAULT_LIMITS = {
14527
14527
  maxInputLogBytes: 2e5,
14528
14528
  maxContextFileBytes: 2e3
14529
14529
  };
14530
- var PLUGIN_VERSION = "0.1.3";
14530
+ var PLUGIN_VERSION = "0.1.5";
14531
14531
  var MINIMUM_HOST_VERSION = "0.0.0";
14532
14532
 
14533
14533
  // src/config/schema.ts
@@ -14677,13 +14677,22 @@ var manifest = {
14677
14677
  description: "Request focused Context Packs before broad repository exploration."
14678
14678
  }],
14679
14679
  ui: {
14680
- slots: [{
14681
- type: "detailTab",
14682
- id: "kujo",
14683
- displayName: "Kujo",
14684
- exportName: "KujoDetailTab",
14685
- entityTypes: ["project", "issue", "run"]
14686
- }]
14680
+ slots: [
14681
+ {
14682
+ type: "detailTab",
14683
+ id: "kujo",
14684
+ displayName: "Kujo",
14685
+ exportName: "KujoDetailTab",
14686
+ entityTypes: ["project", "issue", "run"]
14687
+ },
14688
+ {
14689
+ type: "taskDetailView",
14690
+ id: "kujo-task-view",
14691
+ displayName: "Kujo",
14692
+ exportName: "KujoTaskDetailView",
14693
+ entityTypes: ["issue"]
14694
+ }
14695
+ ]
14687
14696
  }
14688
14697
  };
14689
14698
  var manifest_default = manifest;
package/dist/ui/index.js CHANGED
@@ -1,122 +1,254 @@
1
1
  // src/ui/index.tsx
2
2
  import { useState } from "react";
3
- import { StatusBadge, Spinner, usePluginAction, usePluginData } from "@paperclipai/plugin-sdk/ui";
3
+ import {
4
+ StatusBadge,
5
+ Spinner,
6
+ usePluginAction,
7
+ usePluginData
8
+ } from "@paperclipai/plugin-sdk/ui";
4
9
  import { jsx, jsxs } from "react/jsx-runtime";
5
- var card = { border: "1px solid var(--border, #ddd)", borderRadius: 8, padding: 16, display: "grid", gap: 10 };
6
- var grid = { display: "grid", gap: 16 };
7
- var metrics = { display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(120px, 1fr))", gap: 12 };
8
- function ReviewSection({ review }) {
9
- if (!review) return /* @__PURE__ */ jsxs("section", { style: card, children: [
10
- /* @__PURE__ */ jsx("strong", { children: "Review Pack" }),
11
- /* @__PURE__ */ jsx("span", { children: "Not generated" })
12
- ] });
13
- return /* @__PURE__ */ jsxs("section", { style: card, children: [
14
- /* @__PURE__ */ jsxs("div", { style: { display: "flex", justifyContent: "space-between" }, children: [
15
- /* @__PURE__ */ jsx("strong", { children: "Review Pack" }),
16
- /* @__PURE__ */ jsx(
17
- StatusBadge,
10
+ var colors = {
11
+ ink: "var(--foreground, #111111)",
12
+ muted: "var(--muted-foreground, #6b7280)",
13
+ border: "var(--border, #e5e7eb)",
14
+ surface: "var(--card, #ffffff)",
15
+ canvas: "var(--background, #ffffff)",
16
+ soft: "var(--muted, #f5f5f5)",
17
+ danger: "var(--destructive, #b42318)"
18
+ };
19
+ var panel = {
20
+ color: colors.ink,
21
+ display: "grid",
22
+ gap: 16,
23
+ width: "100%",
24
+ fontFamily: "inherit"
25
+ };
26
+ var card = {
27
+ background: colors.surface,
28
+ border: `1px solid ${colors.border}`,
29
+ borderRadius: 14,
30
+ boxShadow: "0 1px 2px rgba(0, 0, 0, 0.04)",
31
+ display: "grid",
32
+ gap: 14,
33
+ padding: 18
34
+ };
35
+ var hero = {
36
+ ...card,
37
+ alignItems: "center",
38
+ background: `linear-gradient(135deg, ${colors.surface} 0%, ${colors.soft} 100%)`,
39
+ gridTemplateColumns: "auto minmax(0, 1fr) auto"
40
+ };
41
+ var actionGrid = {
42
+ display: "grid",
43
+ gap: 14,
44
+ gridTemplateColumns: "repeat(auto-fit, minmax(240px, 1fr))"
45
+ };
46
+ var actionCard = {
47
+ background: colors.canvas,
48
+ border: `1px solid ${colors.border}`,
49
+ borderRadius: 12,
50
+ display: "flex",
51
+ flexDirection: "column",
52
+ gap: 10,
53
+ minWidth: 0,
54
+ padding: 16
55
+ };
56
+ var input = {
57
+ background: colors.canvas,
58
+ border: `1px solid ${colors.border}`,
59
+ borderRadius: 9,
60
+ boxSizing: "border-box",
61
+ color: colors.ink,
62
+ display: "block",
63
+ font: "inherit",
64
+ fontSize: 13,
65
+ lineHeight: 1.45,
66
+ marginTop: 6,
67
+ outline: "none",
68
+ padding: "10px 12px",
69
+ resize: "vertical",
70
+ width: "100%"
71
+ };
72
+ var buttonBase = {
73
+ alignItems: "center",
74
+ borderRadius: 9,
75
+ cursor: "pointer",
76
+ display: "inline-flex",
77
+ font: "inherit",
78
+ fontSize: 13,
79
+ fontWeight: 650,
80
+ gap: 7,
81
+ justifyContent: "center",
82
+ lineHeight: 1,
83
+ minHeight: 38,
84
+ padding: "10px 14px",
85
+ transition: "opacity 120ms ease, transform 120ms ease"
86
+ };
87
+ var primaryButton = {
88
+ ...buttonBase,
89
+ background: colors.ink,
90
+ border: `1px solid ${colors.ink}`,
91
+ color: colors.canvas,
92
+ boxShadow: "0 1px 2px rgba(0, 0, 0, 0.14)"
93
+ };
94
+ var secondaryButton = {
95
+ ...buttonBase,
96
+ background: colors.canvas,
97
+ border: `1px solid ${colors.border}`,
98
+ color: colors.ink
99
+ };
100
+ var dangerButton = {
101
+ ...secondaryButton,
102
+ color: colors.danger
103
+ };
104
+ var eyebrow = {
105
+ color: colors.muted,
106
+ fontSize: 11,
107
+ fontWeight: 700,
108
+ letterSpacing: "0.09em",
109
+ textTransform: "uppercase"
110
+ };
111
+ var muted = { color: colors.muted, fontSize: 13, lineHeight: 1.5 };
112
+ function KujoMark() {
113
+ return /* @__PURE__ */ jsx(
114
+ "svg",
115
+ {
116
+ "aria-label": "Kujo logo",
117
+ role: "img",
118
+ viewBox: "0 0 1527 1536",
119
+ style: {
120
+ color: colors.ink,
121
+ display: "block",
122
+ flex: "0 0 auto",
123
+ height: 42,
124
+ width: 42
125
+ },
126
+ children: /* @__PURE__ */ jsx(
127
+ "path",
18
128
  {
19
- status: review.footprint.riskLevel === "high" ? "error" : review.footprint.riskLevel === "medium" ? "warning" : "ok",
20
- label: `${review.footprint.riskLevel.toUpperCase()} BLAST RADIUS`
129
+ fill: "currentColor",
130
+ fillRule: "evenodd",
131
+ d: "M0 0 H1527 V1536 H0 Z M178 234 L593 234 L593 700 L597 699 L1008 235 L1350 234 L1332 258 L594 1080 L592 1350 L294 1349 L293 427 L281 361 L260 310 L244 287 L222 264 L178 234 Z M1006 721 L1036 746 L1078 789 L1118 839 L1153 894 L1181 950 L1199 997 L1213 1043 L1225 1101 L1232 1157 L1233 1234 L1222 1328 L1208 1385 L1187 1445 L1159 1503 L1139 1536 L1038 1536 L1036 1455 L1025 1383 L1002 1304 L969 1231 L930 1169 L879 1108 L821 1056 L749 1009 L1006 721 Z M1010 805 L965 854 L962 862 L1011 911 L1055 969 L1094 1036 L1120 1097 L1139 1159 L1153 1232 L1157 1275 L1155 1361 L1171 1284 L1176 1221 L1171 1129 L1157 1056 L1132 981 L1100 917 L1046 841 L1010 805 Z"
21
132
  }
22
133
  )
134
+ }
135
+ );
136
+ }
137
+ function ActionButton({ children, disabled, onClick, tone = "primary" }) {
138
+ const style = tone === "primary" ? primaryButton : tone === "danger" ? dangerButton : secondaryButton;
139
+ return /* @__PURE__ */ jsx(
140
+ "button",
141
+ {
142
+ type: "button",
143
+ disabled,
144
+ onClick,
145
+ style: { ...style, ...disabled ? { cursor: "not-allowed", opacity: 0.45 } : {} },
146
+ children
147
+ }
148
+ );
149
+ }
150
+ function SectionTitle({ title, detail, badge }) {
151
+ return /* @__PURE__ */ jsxs("div", { style: { alignItems: "flex-start", display: "flex", gap: 12, justifyContent: "space-between" }, children: [
152
+ /* @__PURE__ */ jsxs("div", { style: { display: "grid", gap: 4 }, children: [
153
+ /* @__PURE__ */ jsx("strong", { style: { fontSize: 15 }, children: title }),
154
+ /* @__PURE__ */ jsx("span", { style: muted, children: detail })
23
155
  ] }),
24
- review.stale && /* @__PURE__ */ jsx("div", { role: "alert", children: "This review was generated for an earlier workspace state." }),
25
- /* @__PURE__ */ jsxs("div", { style: metrics, children: [
26
- /* @__PURE__ */ jsxs("span", { children: [
27
- /* @__PURE__ */ jsx("b", { children: review.footprint.filesChanged }),
28
- /* @__PURE__ */ jsx("br", {}),
29
- "files changed"
30
- ] }),
31
- /* @__PURE__ */ jsxs("span", { children: [
32
- /* @__PURE__ */ jsxs("b", { children: [
33
- "+",
34
- review.footprint.additions,
35
- " / -",
36
- review.footprint.deletions
37
- ] }),
38
- /* @__PURE__ */ jsx("br", {}),
39
- "lines"
40
- ] }),
41
- /* @__PURE__ */ jsxs("span", { children: [
42
- /* @__PURE__ */ jsx("b", { children: review.footprint.churn }),
43
- /* @__PURE__ */ jsx("br", {}),
44
- "lines churn"
45
- ] })
46
- ] }),
156
+ badge
157
+ ] });
158
+ }
159
+ function EmptySection({ title, detail }) {
160
+ return /* @__PURE__ */ jsx("section", { style: card, children: /* @__PURE__ */ jsx(SectionTitle, { title, detail, badge: /* @__PURE__ */ jsx(StatusBadge, { status: "pending", label: "NOT GENERATED" }) }) });
161
+ }
162
+ function ReviewSection({ review }) {
163
+ if (!review) return /* @__PURE__ */ jsx(EmptySection, { title: "Review Pack", detail: "Generate a bounded summary of the current workspace changes." });
164
+ return /* @__PURE__ */ jsxs("section", { style: card, children: [
165
+ /* @__PURE__ */ jsx(
166
+ SectionTitle,
167
+ {
168
+ title: "Review Pack",
169
+ detail: "Change size, risk signals, and suggested checks.",
170
+ badge: /* @__PURE__ */ jsx(
171
+ StatusBadge,
172
+ {
173
+ status: review.footprint.riskLevel === "high" ? "error" : review.footprint.riskLevel === "medium" ? "warning" : "ok",
174
+ label: `${review.footprint.riskLevel.toUpperCase()} RISK`
175
+ }
176
+ )
177
+ }
178
+ ),
179
+ review.stale && /* @__PURE__ */ jsx("div", { role: "alert", style: { ...muted, color: colors.danger }, children: "This review is stale. Generate a new Review Pack before using it." }),
180
+ /* @__PURE__ */ jsx("div", { style: { display: "grid", gap: 10, gridTemplateColumns: "repeat(auto-fit, minmax(130px, 1fr))" }, children: [
181
+ [review.footprint.filesChanged, "Files changed"],
182
+ [`+${review.footprint.additions} / -${review.footprint.deletions}`, "Line delta"],
183
+ [review.footprint.churn, "Lines churn"]
184
+ ].map(([value, label]) => /* @__PURE__ */ jsxs("div", { style: { background: colors.soft, borderRadius: 10, display: "grid", gap: 3, padding: 12 }, children: [
185
+ /* @__PURE__ */ jsx("strong", { style: { fontSize: 18 }, children: value }),
186
+ /* @__PURE__ */ jsx("span", { style: eyebrow, children: label })
187
+ ] }, label)) }),
47
188
  review.footprint.signals.length > 0 && /* @__PURE__ */ jsxs("div", { children: [
48
- /* @__PURE__ */ jsx("b", { children: "Signals" }),
49
- /* @__PURE__ */ jsx("ul", { children: review.footprint.signals.map((signal) => /* @__PURE__ */ jsx("li", { children: signal.message }, signal.id)) })
189
+ /* @__PURE__ */ jsx("strong", { style: { fontSize: 13 }, children: "Signals" }),
190
+ /* @__PURE__ */ jsx("ul", { style: { ...muted, marginBottom: 0, paddingLeft: 20 }, children: review.footprint.signals.map((signal) => /* @__PURE__ */ jsx("li", { children: signal.message }, signal.id)) })
50
191
  ] }),
51
192
  /* @__PURE__ */ jsxs("div", { children: [
52
- /* @__PURE__ */ jsx("b", { children: "Suggested verification" }),
53
- /* @__PURE__ */ jsx("div", { style: { fontSize: 12 }, children: "Suggestions only \u2014 no command is claimed as executed." }),
54
- /* @__PURE__ */ jsx("ul", { children: review.suggestedTests.slice(0, 12).map((test) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx("code", { children: test.command }) }, test.command)) })
193
+ /* @__PURE__ */ jsx("strong", { style: { fontSize: 13 }, children: "Suggested verification" }),
194
+ /* @__PURE__ */ jsx("div", { style: muted, children: "Suggestions only. Kujo does not claim these commands ran." }),
195
+ /* @__PURE__ */ jsx("ul", { style: { marginBottom: 0, paddingLeft: 20 }, children: review.suggestedTests.slice(0, 12).map((test) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx("code", { children: test.command }) }, test.command)) })
55
196
  ] }),
56
- /* @__PURE__ */ jsx("small", { children: "Generated with Kujo ChangeBucket + PatchBrief" })
197
+ /* @__PURE__ */ jsx("span", { style: eyebrow, children: "ChangeBucket + PatchBrief" })
57
198
  ] });
58
199
  }
59
200
  function FailureSection({ failure }) {
60
- if (!failure) return /* @__PURE__ */ jsxs("section", { style: card, children: [
61
- /* @__PURE__ */ jsx("strong", { children: "Failure Evidence" }),
62
- /* @__PURE__ */ jsx("span", { children: "None" })
63
- ] });
201
+ if (!failure) return /* @__PURE__ */ jsx(EmptySection, { title: "Failure Evidence", detail: "No redacted failure record has been captured." });
64
202
  return /* @__PURE__ */ jsxs("section", { style: card, children: [
65
- /* @__PURE__ */ jsxs("div", { style: { display: "flex", justifyContent: "space-between" }, children: [
66
- /* @__PURE__ */ jsx("strong", { children: "Failure Evidence" }),
67
- /* @__PURE__ */ jsx(StatusBadge, { status: "error", label: "FAILED" })
68
- ] }),
69
- /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx("b", { children: failure.failure.title }) }),
203
+ /* @__PURE__ */ jsx(SectionTitle, { title: "Failure Evidence", detail: failure.failure.title, badge: /* @__PURE__ */ jsx(StatusBadge, { status: "error", label: "CAPTURED" }) }),
70
204
  failure.failure.command && /* @__PURE__ */ jsxs("div", { children: [
71
- /* @__PURE__ */ jsx("small", { children: "Command" }),
205
+ /* @__PURE__ */ jsx("span", { style: eyebrow, children: "Command" }),
72
206
  /* @__PURE__ */ jsx("br", {}),
73
207
  /* @__PURE__ */ jsx("code", { children: failure.failure.command })
74
208
  ] }),
75
- failure.failure.exitCode !== void 0 && /* @__PURE__ */ jsxs("div", { children: [
76
- "Exit code: ",
77
- failure.failure.exitCode
78
- ] }),
79
- /* @__PURE__ */ jsxs("div", { children: [
80
- "Redaction applied: ",
209
+ /* @__PURE__ */ jsxs("div", { style: muted, children: [
210
+ failure.failure.exitCode !== void 0 ? `Exit code ${failure.failure.exitCode} \xB7 ` : "",
81
211
  failure.redaction.redactedCount,
82
- " match(es)"
212
+ " sensitive match(es) redacted"
83
213
  ] }),
84
- failure.evidence.map((item) => /* @__PURE__ */ jsxs("details", { children: [
85
- /* @__PURE__ */ jsxs("summary", { children: [
214
+ failure.evidence.map((item) => /* @__PURE__ */ jsxs("details", { style: { background: colors.soft, borderRadius: 10, padding: 12 }, children: [
215
+ /* @__PURE__ */ jsxs("summary", { style: { cursor: "pointer", fontSize: 13, fontWeight: 650 }, children: [
86
216
  item.label,
87
- item.truncated ? " (truncated)" : ""
217
+ item.truncated ? " \xB7 truncated" : ""
88
218
  ] }),
89
- /* @__PURE__ */ jsx("pre", { style: { whiteSpace: "pre-wrap", maxHeight: 320, overflow: "auto" }, children: item.content })
219
+ /* @__PURE__ */ jsx("pre", { style: { fontSize: 12, marginBottom: 0, maxHeight: 320, overflow: "auto", whiteSpace: "pre-wrap" }, children: item.content })
90
220
  ] }, item.label)),
91
- /* @__PURE__ */ jsx("small", { children: "Captured with Kujo CaseFile" })
221
+ /* @__PURE__ */ jsx("span", { style: eyebrow, children: "CaseFile" })
92
222
  ] });
93
223
  }
94
224
  function ContextSection({ context }) {
95
- if (!context) return /* @__PURE__ */ jsxs("section", { style: card, children: [
96
- /* @__PURE__ */ jsx("strong", { children: "Context Pack" }),
97
- /* @__PURE__ */ jsx("span", { children: "Available" })
98
- ] });
225
+ if (!context) return /* @__PURE__ */ jsx(EmptySection, { title: "Context Pack", detail: "Select the files that matter before an agent reads broadly." });
99
226
  return /* @__PURE__ */ jsxs("section", { style: card, children: [
100
- /* @__PURE__ */ jsx("strong", { children: "Context Pack" }),
101
- /* @__PURE__ */ jsx("div", { children: context.task }),
102
- /* @__PURE__ */ jsxs("div", { children: [
227
+ /* @__PURE__ */ jsx(
228
+ SectionTitle,
229
+ {
230
+ title: "Context Pack",
231
+ detail: context.task,
232
+ badge: /* @__PURE__ */ jsx(StatusBadge, { status: context.stale ? "warning" : "ok", label: context.stale ? "STALE" : "READY" })
233
+ }
234
+ ),
235
+ /* @__PURE__ */ jsxs("div", { style: { ...muted, fontWeight: 600 }, children: [
103
236
  context.files.length,
104
- " relevant files \xB7 about ",
237
+ " files \xB7 about ",
105
238
  context.estimatedTokens.toLocaleString(),
106
239
  " tokens \xB7 ",
107
- context.depth
240
+ context.depth,
241
+ " depth"
108
242
  ] }),
109
- context.stale && /* @__PURE__ */ jsx("div", { role: "alert", children: "This context was generated for an earlier workspace state." }),
110
- /* @__PURE__ */ jsx("ul", { children: context.files.slice(0, 20).map((file) => /* @__PURE__ */ jsxs("li", { children: [
111
- /* @__PURE__ */ jsx("code", { children: file.path }),
112
- /* @__PURE__ */ jsx("br", {}),
113
- /* @__PURE__ */ jsx("small", { children: file.reason })
243
+ /* @__PURE__ */ jsx("div", { style: { display: "grid", gap: 8 }, children: context.files.slice(0, 20).map((file) => /* @__PURE__ */ jsxs("div", { style: { background: colors.soft, borderRadius: 9, display: "grid", gap: 3, padding: "10px 12px" }, children: [
244
+ /* @__PURE__ */ jsx("code", { style: { fontSize: 12 }, children: file.path }),
245
+ /* @__PURE__ */ jsx("span", { style: muted, children: file.reason })
114
246
  ] }, file.path)) }),
115
- context.truncated && /* @__PURE__ */ jsx("div", { children: "Selection was bounded by the configured budget." }),
116
- /* @__PURE__ */ jsx("small", { children: "Selected with Kujo Scent" })
247
+ context.truncated && /* @__PURE__ */ jsx("div", { style: muted, children: "The configured token budget bounded this selection." }),
248
+ /* @__PURE__ */ jsx("span", { style: eyebrow, children: "Scent" })
117
249
  ] });
118
250
  }
119
- function KujoDetailTab({ context }) {
251
+ function KujoPanel({ context, compact = false }) {
120
252
  const { data, loading, error, refresh } = usePluginData("detail", { entityType: context.entityType, entityId: context.entityId });
121
253
  const generateReview = usePluginAction("generate-review");
122
254
  const generateContext = usePluginAction("generate-context");
@@ -140,40 +272,112 @@ function KujoDetailTab({ context }) {
140
272
  setBusy(null);
141
273
  }
142
274
  }
143
- if (loading) return /* @__PURE__ */ jsx(Spinner, { label: "Loading Kujo artifacts" });
144
- if (error) return /* @__PURE__ */ jsxs("div", { role: "alert", children: [
145
- "Unable to load Kujo artifacts: ",
275
+ if (loading) return /* @__PURE__ */ jsx(Spinner, { label: "Loading Kujo workspace intelligence" });
276
+ if (error) return /* @__PURE__ */ jsxs("div", { role: "alert", style: { ...card, color: colors.danger }, children: [
277
+ "Unable to load Kujo: ",
146
278
  error.message
147
279
  ] });
148
- return /* @__PURE__ */ jsxs("div", { style: grid, children: [
149
- /* @__PURE__ */ jsxs("header", { children: [
150
- /* @__PURE__ */ jsx("h2", { style: { marginBottom: 4 }, children: "Kujo" }),
151
- /* @__PURE__ */ jsx("div", { children: "Scope, review, and reproduce agent work." })
280
+ const hasArtifacts = Boolean(data?.review || data?.failure || data?.context);
281
+ return /* @__PURE__ */ jsxs("div", { style: { ...panel, ...compact ? { marginTop: 12 } : {} }, children: [
282
+ /* @__PURE__ */ jsxs("header", { style: hero, children: [
283
+ /* @__PURE__ */ jsx(KujoMark, {}),
284
+ /* @__PURE__ */ jsxs("div", { style: { display: "grid", gap: 3, minWidth: 0 }, children: [
285
+ /* @__PURE__ */ jsx("span", { style: eyebrow, children: "Workspace intelligence" }),
286
+ /* @__PURE__ */ jsx("strong", { style: { fontSize: compact ? 17 : 20, letterSpacing: "-0.02em" }, children: "Kujo" }),
287
+ /* @__PURE__ */ jsx("span", { style: muted, children: "Scope the work. Review the change. Preserve the evidence." })
288
+ ] }),
289
+ /* @__PURE__ */ jsx(StatusBadge, { status: "ok", label: "READY" })
152
290
  ] }),
153
- actionError && /* @__PURE__ */ jsx("div", { role: "alert", children: actionError }),
291
+ actionError && /* @__PURE__ */ jsx("div", { role: "alert", style: { ...card, borderColor: colors.danger, color: colors.danger }, children: actionError }),
154
292
  canGenerate && /* @__PURE__ */ jsxs("section", { style: card, children: [
155
- /* @__PURE__ */ jsx("div", { style: { display: "flex", gap: 8, flexWrap: "wrap" }, children: /* @__PURE__ */ jsx("button", { disabled: busy !== null, onClick: () => run("review", () => generateReview({ entityType: context.entityType, entityId: context.entityId })), children: busy === "review" ? "Generating\u2026" : "Generate Review Pack" }) }),
156
- /* @__PURE__ */ jsxs("label", { children: [
157
- "Task for Context Pack",
158
- /* @__PURE__ */ jsx("input", { value: task, onChange: (event) => setTask(event.target.value), maxLength: 1e4, style: { display: "block", width: "100%" } })
293
+ /* @__PURE__ */ jsxs("div", { children: [
294
+ /* @__PURE__ */ jsx("div", { style: eyebrow, children: "Actions" }),
295
+ /* @__PURE__ */ jsx("strong", { style: { display: "block", fontSize: 16, marginTop: 4 }, children: "Create a reviewable work record" })
159
296
  ] }),
160
- /* @__PURE__ */ jsx("button", { disabled: busy !== null || !task.trim(), onClick: () => run("context", () => generateContext({ entityType: context.entityType, entityId: context.entityId, task, depth: "focused" })), children: busy === "context" ? "Selecting\u2026" : "Generate Context Pack" }),
161
- /* @__PURE__ */ jsxs("label", { children: [
162
- "Failure title",
163
- /* @__PURE__ */ jsx("input", { value: failureTitle, onChange: (event) => setFailureTitle(event.target.value), maxLength: 200, style: { display: "block", width: "100%" } })
164
- ] }),
165
- /* @__PURE__ */ jsxs("label", { children: [
166
- "Bounded failure log",
167
- /* @__PURE__ */ jsx("textarea", { value: failureLog, onChange: (event) => setFailureLog(event.target.value), maxLength: 2e5, rows: 5, style: { display: "block", width: "100%" } })
168
- ] }),
169
- /* @__PURE__ */ jsx("button", { disabled: busy !== null || !failureTitle.trim(), onClick: () => run("failure", () => captureFailure({ entityType: context.entityType, entityId: context.entityId, title: failureTitle, log: failureLog })), children: busy === "failure" ? "Capturing\u2026" : "Capture Failure Evidence" }),
170
- /* @__PURE__ */ jsx("button", { disabled: busy !== null, onClick: () => run("clear", () => clearArtifacts({ entityType: context.entityType, entityId: context.entityId })), children: busy === "clear" ? "Clearing\u2026" : "Clear Kujo data" })
297
+ /* @__PURE__ */ jsxs("div", { style: actionGrid, children: [
298
+ /* @__PURE__ */ jsxs("div", { style: actionCard, children: [
299
+ /* @__PURE__ */ jsx(SectionTitle, { title: "Review changes", detail: "Measure blast radius and prepare a review handoff." }),
300
+ /* @__PURE__ */ jsx("div", { style: { flex: 1 } }),
301
+ /* @__PURE__ */ jsxs(ActionButton, { disabled: busy !== null, onClick: () => run("review", () => generateReview({ entityType: context.entityType, entityId: context.entityId })), children: [
302
+ busy === "review" ? "Generating\u2026" : "Generate Review Pack",
303
+ " ",
304
+ /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: "\u2192" })
305
+ ] })
306
+ ] }),
307
+ /* @__PURE__ */ jsxs("div", { style: actionCard, children: [
308
+ /* @__PURE__ */ jsx(SectionTitle, { title: "Select context", detail: "Build a focused, bounded file set for a task." }),
309
+ /* @__PURE__ */ jsxs("label", { style: { ...eyebrow, display: "block" }, children: [
310
+ "Task",
311
+ /* @__PURE__ */ jsx(
312
+ "textarea",
313
+ {
314
+ value: task,
315
+ onChange: (event) => setTask(event.target.value),
316
+ maxLength: 1e4,
317
+ placeholder: "What should the agent investigate?",
318
+ rows: 3,
319
+ style: input
320
+ }
321
+ )
322
+ ] }),
323
+ /* @__PURE__ */ jsxs(ActionButton, { disabled: busy !== null || !task.trim(), onClick: () => run("context", () => generateContext({ entityType: context.entityType, entityId: context.entityId, task, depth: "focused" })), children: [
324
+ busy === "context" ? "Selecting\u2026" : "Generate Context Pack",
325
+ " ",
326
+ /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: "\u2192" })
327
+ ] })
328
+ ] }),
329
+ /* @__PURE__ */ jsxs("div", { style: actionCard, children: [
330
+ /* @__PURE__ */ jsx(SectionTitle, { title: "Capture a failure", detail: "Store bounded logs with sensitive values redacted." }),
331
+ /* @__PURE__ */ jsxs("label", { style: { ...eyebrow, display: "block" }, children: [
332
+ "Title",
333
+ /* @__PURE__ */ jsx(
334
+ "input",
335
+ {
336
+ value: failureTitle,
337
+ onChange: (event) => setFailureTitle(event.target.value),
338
+ maxLength: 200,
339
+ placeholder: "CI verification failure",
340
+ style: input
341
+ }
342
+ )
343
+ ] }),
344
+ /* @__PURE__ */ jsxs("label", { style: { ...eyebrow, display: "block" }, children: [
345
+ "Bounded log",
346
+ /* @__PURE__ */ jsx(
347
+ "textarea",
348
+ {
349
+ value: failureLog,
350
+ onChange: (event) => setFailureLog(event.target.value),
351
+ maxLength: 2e5,
352
+ placeholder: "Paste the relevant output here.",
353
+ rows: 3,
354
+ style: input
355
+ }
356
+ )
357
+ ] }),
358
+ /* @__PURE__ */ jsxs(ActionButton, { disabled: busy !== null || !failureTitle.trim(), onClick: () => run("failure", () => captureFailure({ entityType: context.entityType, entityId: context.entityId, title: failureTitle, log: failureLog })), children: [
359
+ busy === "failure" ? "Capturing\u2026" : "Capture Failure Evidence",
360
+ " ",
361
+ /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: "\u2192" })
362
+ ] })
363
+ ] })
364
+ ] })
365
+ ] }),
366
+ /* @__PURE__ */ jsxs("div", { style: { display: "grid", gap: 12 }, children: [
367
+ /* @__PURE__ */ jsx(ReviewSection, { review: data?.review ?? null }),
368
+ /* @__PURE__ */ jsx(FailureSection, { failure: data?.failure ?? null }),
369
+ /* @__PURE__ */ jsx(ContextSection, { context: data?.context ?? null })
171
370
  ] }),
172
- /* @__PURE__ */ jsx(ReviewSection, { review: data?.review ?? null }),
173
- /* @__PURE__ */ jsx(FailureSection, { failure: data?.failure ?? null }),
174
- /* @__PURE__ */ jsx(ContextSection, { context: data?.context ?? null })
371
+ hasArtifacts && /* @__PURE__ */ jsx("div", { style: { display: "flex", justifyContent: "flex-end" }, children: /* @__PURE__ */ jsx(ActionButton, { tone: "danger", disabled: busy !== null, onClick: () => run("clear", () => clearArtifacts({ entityType: context.entityType, entityId: context.entityId })), children: busy === "clear" ? "Clearing\u2026" : "Clear Kujo data" }) })
175
372
  ] });
176
373
  }
374
+ function KujoDetailTab(props) {
375
+ return /* @__PURE__ */ jsx(KujoPanel, { ...props });
376
+ }
377
+ function KujoTaskDetailView(props) {
378
+ return /* @__PURE__ */ jsx(KujoPanel, { ...props, compact: true });
379
+ }
177
380
  export {
178
- KujoDetailTab
381
+ KujoDetailTab,
382
+ KujoTaskDetailView
179
383
  };
package/dist/worker.js CHANGED
@@ -28710,7 +28710,7 @@ var CONTEXT_BUDGETS = {
28710
28710
  focused: 16e3,
28711
28711
  broad: 4e4
28712
28712
  };
28713
- var PLUGIN_VERSION = "0.1.3";
28713
+ var PLUGIN_VERSION = "0.1.5";
28714
28714
  var PAPERCLIP_API_VERSION = 1;
28715
28715
 
28716
28716
  // src/config/schema.ts
@@ -14,12 +14,13 @@
14
14
  - `projects.read`, `project.workspaces.read`: canonical workspace resolution only
15
15
  - `plugin.state.read`, `plugin.state.write`: normalized artifact persistence
16
16
  - `ui.detailTab.register`: one shared Kujo tab on project/issue/run details
17
+ - `ui.taskDetailView.register`: an inline Kujo workspace in the current issue view
17
18
  - `skills.managed`: optional Scoped Repository Context guidance
18
19
 
19
20
  The plugin requests no HTTP, secret, issue-write, approval, budget, database, job, webhook, or arbitrary local-folder capability.
20
21
 
21
22
  ## UI walkthrough
22
23
 
23
- The shared Kujo tab starts with runtime/artifact status. Issue/project views provide **Generate Review Pack**, **Generate Context Pack**, and **Capture Failure Evidence** actions. Review shows blast radius, explainable signals, and clearly labeled suggested verification. Failure Evidence shows bounded excerpts and redaction counts. Context shows selected paths, reasons, estimated tokens, depth, and stale/budget status. Run views show associated persisted evidence without exposing a terminal.
24
+ Kujo appears automatically in the current issue view and remains available as a shared detail tab on project, issue detail, and run pages. The workspace presents **Generate Review Pack**, **Generate Context Pack**, and **Capture Failure Evidence** as distinct, styled actions. Review shows blast radius, explainable signals, and clearly labeled suggested verification. Failure Evidence shows bounded excerpts and redaction counts. Context shows selected paths, reasons, estimated tokens, depth, and stale/budget status. Run views show associated persisted evidence without exposing a terminal.
24
25
 
25
26
  Catalog review should require the tagged cross-platform workflow, npm provenance for all six runtime packages and this plugin, install/upgrade/uninstall evidence on the declared minimum host, and the security assertions in `THREAT_MODEL.md`.
@@ -12,7 +12,7 @@
12
12
  npx paperclipai plugin install @kujolang/paperclip
13
13
  ```
14
14
 
15
- Restart Paperclip if it is running. Open a project, issue, or run, select the **Kujo** tab, and check the status panel.
15
+ Restart Paperclip if it is running. Open an issue and confirm that the Kujo workspace appears in the current task view. On project and run pages, open the **Kujo** tab. No Classic Task Interface setting is required.
16
16
 
17
17
  The package installs `@kujolang/kujo-runtime` and one matching optional native package. Supported targets are macOS arm64/x64, Linux arm64/x64, and Windows x64. No Kujo package uses `preinstall`, `install`, or `postinstall`.
18
18
 
package/docs/USAGE.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  ## Paperclip UI
4
4
 
5
- Open the **Kujo** detail tab on a project or issue.
5
+ Open an issue and Kujo appears inline in Paperclip's current task view. There is no Classic Task Interface prerequisite. Project, issue detail, and run pages also expose the **Kujo** detail tab where the host supports tabs.
6
6
 
7
7
  - **Generate Review Pack** measures the current working tree and builds a handoff.
8
8
  - **Generate Context Pack** selects files for a task at minimal, focused, or broad depth.
@@ -10,6 +10,8 @@ Open the **Kujo** detail tab on a project or issue.
10
10
 
11
11
  Run views display saved evidence. They do not expose a terminal.
12
12
 
13
+ The inline workspace and detail tab use the same actions and persisted artifacts, so changing views does not create a second copy of Kujo data.
14
+
13
15
  ## Agent tools
14
16
 
15
17
  ### Review changes
package/package.json CHANGED
@@ -1,11 +1,16 @@
1
1
  {
2
2
  "name": "@kujolang/paperclip",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "description": "Make Paperclip agent work easier to scope, review, reproduce, and verify.",
5
5
  "license": "MIT",
6
6
  "homepage": "https://github.com/kujolang/paperclip#readme",
7
- "bugs": { "url": "https://github.com/kujolang/paperclip/issues" },
8
- "repository": { "type": "git", "url": "git+https://github.com/kujolang/paperclip.git" },
7
+ "bugs": {
8
+ "url": "https://github.com/kujolang/paperclip/issues"
9
+ },
10
+ "repository": {
11
+ "type": "git",
12
+ "url": "git+https://github.com/kujolang/paperclip.git"
13
+ },
9
14
  "type": "module",
10
15
  "engines": {
11
16
  "node": ">=24.11.0"