@kujolang/paperclip 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/LICENSE +21 -0
  3. package/README.md +116 -0
  4. package/SECURITY.md +35 -0
  5. package/VERSION +1 -0
  6. package/bundled/components/changebucket/LICENSE +9 -0
  7. package/bundled/components/changebucket/changebucket.kujo +12 -0
  8. package/bundled/components/changebucket/src/analyze.kujo +240 -0
  9. package/bundled/components/changebucket/src/budget.kujo +92 -0
  10. package/bundled/components/changebucket/src/classify.kujo +221 -0
  11. package/bundled/components/changebucket/src/cli.kujo +324 -0
  12. package/bundled/components/changebucket/src/diffsrc.kujo +252 -0
  13. package/bundled/components/changebucket/src/render.kujo +346 -0
  14. package/bundled/components/changebucket/src/util.kujo +62 -0
  15. package/bundled/components/context/LICENSE +9 -0
  16. package/bundled/components/context/scent.kujo +3250 -0
  17. package/bundled/components/failure-evidence/LICENSE +9 -0
  18. package/bundled/components/failure-evidence/casefile.kujo +2061 -0
  19. package/bundled/components/patchbrief/LICENSE +9 -0
  20. package/bundled/components/patchbrief/patchbrief.kujo +153 -0
  21. package/bundled/components/patchbrief/schemas/patchbrief-handoff.schema.json +38 -0
  22. package/bundled/components/patchbrief/schemas/patchbrief-summary.schema.json +46 -0
  23. package/bundled/components/patchbrief/src/common.kujo +212 -0
  24. package/bundled/components/patchbrief/src/git.kujo +250 -0
  25. package/bundled/components/patchbrief/src/handoff.kujo +145 -0
  26. package/bundled/components/patchbrief/src/suggest_tests.kujo +137 -0
  27. package/bundled/components/patchbrief/src/summarize.kujo +309 -0
  28. package/bundled/kujo-components.lock.json +134 -0
  29. package/dist/manifest.js +14696 -0
  30. package/dist/ui/index.js +179 -0
  31. package/dist/worker.js +30536 -0
  32. package/docs/ARCHITECTURE.md +28 -0
  33. package/docs/CATALOG_SUBMISSION.md +25 -0
  34. package/docs/COMPATIBILITY.md +21 -0
  35. package/docs/CONFIGURATION.md +33 -0
  36. package/docs/INSTALLATION.md +53 -0
  37. package/docs/OPERATIONS.md +60 -0
  38. package/docs/README.md +18 -0
  39. package/docs/RELEASE_READINESS.md +46 -0
  40. package/docs/THREAT_MODEL.md +26 -0
  41. package/docs/TROUBLESHOOTING.md +12 -0
  42. package/docs/USAGE.md +95 -0
  43. package/examples/agent-workflow.md +20 -0
  44. package/package.json +71 -0
  45. package/schemas/changebucket-analysis.schema.json +25 -0
  46. package/schemas/context-pack.schema.json +23 -0
  47. package/schemas/failure-evidence.schema.json +18 -0
  48. package/schemas/review-pack.schema.json +19 -0
  49. package/skills/scoped-repository-context/SKILL.md +9 -0
@@ -0,0 +1,179 @@
1
+ // src/ui/index.tsx
2
+ import { useState } from "react";
3
+ import { StatusBadge, Spinner, usePluginAction, usePluginData } from "@paperclipai/plugin-sdk/ui";
4
+ 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,
18
+ {
19
+ status: review.footprint.riskLevel === "high" ? "error" : review.footprint.riskLevel === "medium" ? "warning" : "ok",
20
+ label: `${review.footprint.riskLevel.toUpperCase()} BLAST RADIUS`
21
+ }
22
+ )
23
+ ] }),
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
+ ] }),
47
+ 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)) })
50
+ ] }),
51
+ /* @__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)) })
55
+ ] }),
56
+ /* @__PURE__ */ jsx("small", { children: "Generated with Kujo ChangeBucket + PatchBrief" })
57
+ ] });
58
+ }
59
+ 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
+ ] });
64
+ 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 }) }),
70
+ failure.failure.command && /* @__PURE__ */ jsxs("div", { children: [
71
+ /* @__PURE__ */ jsx("small", { children: "Command" }),
72
+ /* @__PURE__ */ jsx("br", {}),
73
+ /* @__PURE__ */ jsx("code", { children: failure.failure.command })
74
+ ] }),
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: ",
81
+ failure.redaction.redactedCount,
82
+ " match(es)"
83
+ ] }),
84
+ failure.evidence.map((item) => /* @__PURE__ */ jsxs("details", { children: [
85
+ /* @__PURE__ */ jsxs("summary", { children: [
86
+ item.label,
87
+ item.truncated ? " (truncated)" : ""
88
+ ] }),
89
+ /* @__PURE__ */ jsx("pre", { style: { whiteSpace: "pre-wrap", maxHeight: 320, overflow: "auto" }, children: item.content })
90
+ ] }, item.label)),
91
+ /* @__PURE__ */ jsx("small", { children: "Captured with Kujo CaseFile" })
92
+ ] });
93
+ }
94
+ 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
+ ] });
99
+ 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: [
103
+ context.files.length,
104
+ " relevant files \xB7 about ",
105
+ context.estimatedTokens.toLocaleString(),
106
+ " tokens \xB7 ",
107
+ context.depth
108
+ ] }),
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 })
114
+ ] }, 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" })
117
+ ] });
118
+ }
119
+ function KujoDetailTab({ context }) {
120
+ const { data, loading, error, refresh } = usePluginData("detail", { entityType: context.entityType, entityId: context.entityId });
121
+ const generateReview = usePluginAction("generate-review");
122
+ const generateContext = usePluginAction("generate-context");
123
+ const captureFailure = usePluginAction("capture-failure");
124
+ const clearArtifacts = usePluginAction("clear-artifacts");
125
+ const [task, setTask] = useState("");
126
+ const [failureTitle, setFailureTitle] = useState("");
127
+ const [failureLog, setFailureLog] = useState("");
128
+ const [busy, setBusy] = useState(null);
129
+ const [actionError, setActionError] = useState(null);
130
+ const canGenerate = context.entityType === "project" || context.entityType === "issue";
131
+ async function run(label, fn) {
132
+ setBusy(label);
133
+ setActionError(null);
134
+ try {
135
+ await fn();
136
+ await refresh();
137
+ } catch (value) {
138
+ setActionError(value instanceof Error ? value.message : String(value));
139
+ } finally {
140
+ setBusy(null);
141
+ }
142
+ }
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: ",
146
+ error.message
147
+ ] });
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." })
152
+ ] }),
153
+ actionError && /* @__PURE__ */ jsx("div", { role: "alert", children: actionError }),
154
+ 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%" } })
159
+ ] }),
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" })
171
+ ] }),
172
+ /* @__PURE__ */ jsx(ReviewSection, { review: data?.review ?? null }),
173
+ /* @__PURE__ */ jsx(FailureSection, { failure: data?.failure ?? null }),
174
+ /* @__PURE__ */ jsx(ContextSection, { context: data?.context ?? null })
175
+ ] });
176
+ }
177
+ export {
178
+ KujoDetailTab
179
+ };