@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.
- package/CHANGELOG.md +18 -0
- package/LICENSE +21 -0
- package/README.md +116 -0
- package/SECURITY.md +35 -0
- package/VERSION +1 -0
- package/bundled/components/changebucket/LICENSE +9 -0
- package/bundled/components/changebucket/changebucket.kujo +12 -0
- package/bundled/components/changebucket/src/analyze.kujo +240 -0
- package/bundled/components/changebucket/src/budget.kujo +92 -0
- package/bundled/components/changebucket/src/classify.kujo +221 -0
- package/bundled/components/changebucket/src/cli.kujo +324 -0
- package/bundled/components/changebucket/src/diffsrc.kujo +252 -0
- package/bundled/components/changebucket/src/render.kujo +346 -0
- package/bundled/components/changebucket/src/util.kujo +62 -0
- package/bundled/components/context/LICENSE +9 -0
- package/bundled/components/context/scent.kujo +3250 -0
- package/bundled/components/failure-evidence/LICENSE +9 -0
- package/bundled/components/failure-evidence/casefile.kujo +2061 -0
- package/bundled/components/patchbrief/LICENSE +9 -0
- package/bundled/components/patchbrief/patchbrief.kujo +153 -0
- package/bundled/components/patchbrief/schemas/patchbrief-handoff.schema.json +38 -0
- package/bundled/components/patchbrief/schemas/patchbrief-summary.schema.json +46 -0
- package/bundled/components/patchbrief/src/common.kujo +212 -0
- package/bundled/components/patchbrief/src/git.kujo +250 -0
- package/bundled/components/patchbrief/src/handoff.kujo +145 -0
- package/bundled/components/patchbrief/src/suggest_tests.kujo +137 -0
- package/bundled/components/patchbrief/src/summarize.kujo +309 -0
- package/bundled/kujo-components.lock.json +134 -0
- package/dist/manifest.js +14696 -0
- package/dist/ui/index.js +179 -0
- package/dist/worker.js +30536 -0
- package/docs/ARCHITECTURE.md +28 -0
- package/docs/CATALOG_SUBMISSION.md +25 -0
- package/docs/COMPATIBILITY.md +21 -0
- package/docs/CONFIGURATION.md +33 -0
- package/docs/INSTALLATION.md +53 -0
- package/docs/OPERATIONS.md +60 -0
- package/docs/README.md +18 -0
- package/docs/RELEASE_READINESS.md +46 -0
- package/docs/THREAT_MODEL.md +26 -0
- package/docs/TROUBLESHOOTING.md +12 -0
- package/docs/USAGE.md +95 -0
- package/examples/agent-workflow.md +20 -0
- package/package.json +71 -0
- package/schemas/changebucket-analysis.schema.json +25 -0
- package/schemas/context-pack.schema.json +23 -0
- package/schemas/failure-evidence.schema.json +18 -0
- package/schemas/review-pack.schema.json +19 -0
- package/skills/scoped-repository-context/SKILL.md +9 -0
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
# Summarize module — analyzes git diff and generates structured summaries.
|
|
2
|
+
|
|
3
|
+
from src.git import is_git_repo, current_branch, repo_name, diff_stat, changed_files_result, full_diff_analysis, recent_commits
|
|
4
|
+
from src.common import str_trim, str_contains, str_lower, str_join, str_starts_with, str_ends_with, markdown_text, markdown_code, print_lines, print_prefixed_lines, print_prefixed_or_fallback, print_markdown_section, print_markdown_paragraph, print_fenced, print_not_git_repo_error
|
|
5
|
+
|
|
6
|
+
# Language/extension to type mapping for summary descriptions.
|
|
7
|
+
LANG_MAP := {
|
|
8
|
+
".kujo": "Kujo",
|
|
9
|
+
".rs": "Rust",
|
|
10
|
+
".py": "Python",
|
|
11
|
+
".js": "JavaScript",
|
|
12
|
+
".ts": "TypeScript",
|
|
13
|
+
".jsx": "React JSX",
|
|
14
|
+
".tsx": "React TSX",
|
|
15
|
+
".php": "PHP",
|
|
16
|
+
".rb": "Ruby",
|
|
17
|
+
".go": "Go",
|
|
18
|
+
".java": "Java",
|
|
19
|
+
".kt": "Kotlin",
|
|
20
|
+
".swift": "Swift",
|
|
21
|
+
".c": "C",
|
|
22
|
+
".cpp": "C++",
|
|
23
|
+
".h": "C/C++ Header",
|
|
24
|
+
".css": "CSS",
|
|
25
|
+
".html": "HTML",
|
|
26
|
+
".md": "Markdown",
|
|
27
|
+
".json": "JSON",
|
|
28
|
+
".yaml": "YAML",
|
|
29
|
+
".yml": "YAML",
|
|
30
|
+
".toml": "TOML",
|
|
31
|
+
".sql": "SQL",
|
|
32
|
+
".sh": "Shell",
|
|
33
|
+
".bash": "Bash",
|
|
34
|
+
".dockerfile": "Docker",
|
|
35
|
+
".tf": "Terraform",
|
|
36
|
+
".xml": "XML"
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
# Get the language label for a file extension.
|
|
40
|
+
export func lang_for_file(file_path) {
|
|
41
|
+
lower := str_lower(file_path)
|
|
42
|
+
if lower == "dockerfile" || str_ends_with(lower, "/dockerfile") || str_ends_with(lower, ".dockerfile") {
|
|
43
|
+
return "Docker"
|
|
44
|
+
}
|
|
45
|
+
# Check each extension
|
|
46
|
+
extensions := [".kujo", ".rs", ".py", ".js", ".tsx", ".ts", ".jsx", ".php", ".rb", ".go", ".java", ".kt", ".swift", ".cpp", ".c", ".h", ".css", ".html", ".md", ".json", ".yaml", ".yml", ".toml", ".sql", ".sh", ".bash", ".tf", ".xml"]
|
|
47
|
+
ei := 0
|
|
48
|
+
while ei < len(extensions) {
|
|
49
|
+
ext := to_string(extensions[ei])
|
|
50
|
+
if str_ends_with(lower, ext) {
|
|
51
|
+
return LANG_MAP[ext]
|
|
52
|
+
}
|
|
53
|
+
ei := ei + 1
|
|
54
|
+
}
|
|
55
|
+
return "Unknown"
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
func file_detail_lines(files_list) {
|
|
59
|
+
lines := []
|
|
60
|
+
fi_idx := 0
|
|
61
|
+
while fi_idx < len(files_list) {
|
|
62
|
+
f := to_string(files_list[fi_idx])
|
|
63
|
+
lang := lang_for_file(f)
|
|
64
|
+
lines := push(lines, "- " + markdown_code(f) + " (" + lang + ")")
|
|
65
|
+
fi_idx := fi_idx + 1
|
|
66
|
+
}
|
|
67
|
+
return lines
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
func push_unique_text(items, value) {
|
|
71
|
+
text := to_string(value)
|
|
72
|
+
idx := 0
|
|
73
|
+
while idx < len(items) {
|
|
74
|
+
if to_string(items[idx]) == text {
|
|
75
|
+
return items
|
|
76
|
+
}
|
|
77
|
+
idx := idx + 1
|
|
78
|
+
}
|
|
79
|
+
return push(items, text)
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
# Analyze changed files and infer likely purpose.
|
|
83
|
+
export func infer_purpose(files_list, diff_text) {
|
|
84
|
+
if len(files_list) == 0 {
|
|
85
|
+
return "No changes detected"
|
|
86
|
+
}
|
|
87
|
+
lower_diff := str_lower(diff_text)
|
|
88
|
+
purposes := []
|
|
89
|
+
# Check for common change patterns
|
|
90
|
+
if str_contains(lower_diff, "test") || str_contains(lower_diff, "spec") {
|
|
91
|
+
purposes := push(purposes, "Testing")
|
|
92
|
+
}
|
|
93
|
+
if str_contains(lower_diff, "fix") || str_contains(lower_diff, "bug") {
|
|
94
|
+
purposes := push(purposes, "Bug fix")
|
|
95
|
+
}
|
|
96
|
+
if str_contains(lower_diff, "feature") || str_contains(lower_diff, "add") {
|
|
97
|
+
purposes := push(purposes, "Feature addition")
|
|
98
|
+
}
|
|
99
|
+
if str_contains(lower_diff, "refactor") || str_contains(lower_diff, "cleanup") {
|
|
100
|
+
purposes := push(purposes, "Refactoring")
|
|
101
|
+
}
|
|
102
|
+
if str_contains(lower_diff, "doc") || str_contains(lower_diff, "readme") {
|
|
103
|
+
purposes := push(purposes, "Documentation")
|
|
104
|
+
}
|
|
105
|
+
if str_contains(lower_diff, "security") || str_contains(lower_diff, "auth") || str_contains(lower_diff, "vuln") {
|
|
106
|
+
purposes := push(purposes, "Security")
|
|
107
|
+
}
|
|
108
|
+
if str_contains(lower_diff, "perf") || str_contains(lower_diff, "optimiz") || str_contains(lower_diff, "speed") {
|
|
109
|
+
purposes := push(purposes, "Performance")
|
|
110
|
+
}
|
|
111
|
+
if str_contains(lower_diff, "config") || str_contains(lower_diff, "setting") {
|
|
112
|
+
purposes := push(purposes, "Configuration")
|
|
113
|
+
}
|
|
114
|
+
if str_contains(lower_diff, "deprecat") || str_contains(lower_diff, "remov") {
|
|
115
|
+
purposes := push(purposes, "Deprecation/Removal")
|
|
116
|
+
}
|
|
117
|
+
if len(purposes) == 0 {
|
|
118
|
+
purposes := push(purposes, "General changes")
|
|
119
|
+
}
|
|
120
|
+
return str_join(purposes, ", ")
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
# Identify risk areas based on changed files.
|
|
124
|
+
export func identify_risks(files_list, diff_text) {
|
|
125
|
+
risks := []
|
|
126
|
+
added_lines := []
|
|
127
|
+
diff_lines := split(to_string(diff_text), "\n")
|
|
128
|
+
di := 0
|
|
129
|
+
while di < len(diff_lines) {
|
|
130
|
+
line := to_string(diff_lines[di])
|
|
131
|
+
if str_starts_with(line, "+") && str_starts_with(line, "+++") == false {
|
|
132
|
+
added_lines := push(added_lines, substring(line, 1, len(line)))
|
|
133
|
+
}
|
|
134
|
+
di := di + 1
|
|
135
|
+
}
|
|
136
|
+
lower_diff := str_lower(str_join(added_lines, "\n"))
|
|
137
|
+
# Check for risky patterns
|
|
138
|
+
fi := 0
|
|
139
|
+
while fi < len(files_list) {
|
|
140
|
+
f := str_lower(to_string(files_list[fi]))
|
|
141
|
+
if str_contains(f, "auth") || str_contains(f, "login") || str_contains(f, "password") || str_contains(f, "token") || str_contains(f, "secret") {
|
|
142
|
+
risks := push_unique_text(risks, "Authentication/authorization changes — review for security implications")
|
|
143
|
+
}
|
|
144
|
+
if str_contains(f, "database") || str_contains(f, "migration") || str_contains(f, "schema") {
|
|
145
|
+
risks := push_unique_text(risks, "Database schema or query changes — verify migration safety")
|
|
146
|
+
}
|
|
147
|
+
if str_contains(f, "api") || str_contains(f, "route") || str_contains(f, "endpoint") || str_contains(f, "handler") {
|
|
148
|
+
risks := push_unique_text(risks, "API/route changes — verify backward compatibility")
|
|
149
|
+
}
|
|
150
|
+
if str_contains(f, "config") || str_contains(f, ".env") || str_contains(f, "setting") {
|
|
151
|
+
risks := push_unique_text(risks, "Configuration changes — verify environment-specific values")
|
|
152
|
+
}
|
|
153
|
+
if str_contains(f, "test") || str_contains(f, "spec") {
|
|
154
|
+
risks := push_unique_text(risks, "Test changes — ensure tests actually validate the intended behavior")
|
|
155
|
+
}
|
|
156
|
+
fi := fi + 1
|
|
157
|
+
}
|
|
158
|
+
if str_contains(lower_diff, "eval(") || str_contains(lower_diff, "exec(") || str_contains(lower_diff, "system(") {
|
|
159
|
+
risks := push(risks, "Dangerous function calls detected (eval/exec/system) — security review required")
|
|
160
|
+
}
|
|
161
|
+
if str_contains(lower_diff, "todo") || str_contains(lower_diff, "fixme") || str_contains(lower_diff, "hack") {
|
|
162
|
+
risks := push(risks, "Unresolved TODO/FIXME/HACK comments — review before merge")
|
|
163
|
+
}
|
|
164
|
+
if len(risks) == 0 {
|
|
165
|
+
risks := push(risks, "No high-risk patterns detected (heuristic check only)")
|
|
166
|
+
}
|
|
167
|
+
return risks
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
# Generate a Markdown summary.
|
|
171
|
+
export func summarize_markdown() {
|
|
172
|
+
if is_git_repo() == false {
|
|
173
|
+
print_not_git_repo_error()
|
|
174
|
+
exit(1)
|
|
175
|
+
}
|
|
176
|
+
branch := current_branch()
|
|
177
|
+
repo := repo_name()
|
|
178
|
+
stat := diff_stat()
|
|
179
|
+
files_result := changed_files_result()
|
|
180
|
+
if files_result["ok"] == false {
|
|
181
|
+
print_lines(["Error: Failed to inspect git working tree."])
|
|
182
|
+
exit(1)
|
|
183
|
+
}
|
|
184
|
+
files := files_result["files"]
|
|
185
|
+
diff_analysis := full_diff_analysis()
|
|
186
|
+
diff_text := diff_analysis["text"]
|
|
187
|
+
if len(files) == 0 && stat["files"] == 0 {
|
|
188
|
+
print_lines([
|
|
189
|
+
"# PatchBrief Summary",
|
|
190
|
+
"",
|
|
191
|
+
"**Repo:** " + markdown_text(repo),
|
|
192
|
+
"**Branch:** " + markdown_text(branch),
|
|
193
|
+
"",
|
|
194
|
+
"No uncommitted changes detected."
|
|
195
|
+
])
|
|
196
|
+
return
|
|
197
|
+
}
|
|
198
|
+
purpose := infer_purpose(files, diff_text)
|
|
199
|
+
risks := identify_risks(files, diff_text)
|
|
200
|
+
if diff_analysis["error"] == true {
|
|
201
|
+
risks := push_unique_text(risks, "Diff content analysis failed — purpose and content-based risk hints may be incomplete")
|
|
202
|
+
} else if diff_analysis["truncated"] == true {
|
|
203
|
+
risks := push_unique_text(risks, "Diff analysis was truncated at " + to_string(diff_analysis["max_bytes"]) + " bytes — purpose and content-based risk hints may be incomplete")
|
|
204
|
+
}
|
|
205
|
+
print_lines([
|
|
206
|
+
"# PatchBrief Summary",
|
|
207
|
+
"",
|
|
208
|
+
"**Repo:** " + markdown_text(repo),
|
|
209
|
+
"**Branch:** " + markdown_text(branch),
|
|
210
|
+
"**Changed Files:** " + to_string(len(files)),
|
|
211
|
+
"**Lines Added:** +" + to_string(stat["added"]),
|
|
212
|
+
"**Lines Removed:** -" + to_string(stat["removed"])
|
|
213
|
+
])
|
|
214
|
+
print_markdown_section("Likely Purpose")
|
|
215
|
+
print_markdown_paragraph(purpose)
|
|
216
|
+
print_markdown_section("Changed Files")
|
|
217
|
+
# Show the git diff --stat output
|
|
218
|
+
if str_trim(stat["output"]) == "" {
|
|
219
|
+
print_fenced("No tracked diff stat available. Untracked files are listed below.")
|
|
220
|
+
} else {
|
|
221
|
+
print_fenced(str_trim(stat["output"]))
|
|
222
|
+
}
|
|
223
|
+
print_markdown_section("File Details")
|
|
224
|
+
print_lines(file_detail_lines(files))
|
|
225
|
+
print_markdown_section("Risk Areas")
|
|
226
|
+
print_prefixed_lines(risks, "- ")
|
|
227
|
+
print_markdown_section("Recent Commits")
|
|
228
|
+
commits_raw := recent_commits(5)
|
|
229
|
+
commits := []
|
|
230
|
+
ci := 0
|
|
231
|
+
while ci < len(commits_raw) {
|
|
232
|
+
commits := push(commits, markdown_text(commits_raw[ci]))
|
|
233
|
+
ci := ci + 1
|
|
234
|
+
}
|
|
235
|
+
print_prefixed_or_fallback(commits, "- ", "No recent commits found.")
|
|
236
|
+
print_lines([
|
|
237
|
+
"",
|
|
238
|
+
"---",
|
|
239
|
+
"*Generated by PatchBrief v1.0.1*"
|
|
240
|
+
])
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
# Generate a JSON summary.
|
|
245
|
+
export func summarize_json(pretty_json) {
|
|
246
|
+
if is_git_repo() == false {
|
|
247
|
+
error_obj := {
|
|
248
|
+
"error": true,
|
|
249
|
+
"message": "Not a git repository. Run patchbrief inside a git repo."
|
|
250
|
+
}
|
|
251
|
+
if pretty_json == true { print(to_json_pretty(error_obj)) } else { print(to_json(error_obj)) }
|
|
252
|
+
exit(1)
|
|
253
|
+
}
|
|
254
|
+
branch := current_branch()
|
|
255
|
+
repo := repo_name()
|
|
256
|
+
stat := diff_stat()
|
|
257
|
+
files_result := changed_files_result()
|
|
258
|
+
if files_result["ok"] == false {
|
|
259
|
+
error_obj := {"error": true, "message": "Failed to inspect git working tree."}
|
|
260
|
+
if pretty_json == true { print(to_json_pretty(error_obj)) } else { print(to_json(error_obj)) }
|
|
261
|
+
exit(1)
|
|
262
|
+
}
|
|
263
|
+
files := files_result["files"]
|
|
264
|
+
diff_analysis := full_diff_analysis()
|
|
265
|
+
diff_text := diff_analysis["text"]
|
|
266
|
+
purpose := infer_purpose(files, diff_text)
|
|
267
|
+
risks := identify_risks(files, diff_text)
|
|
268
|
+
if diff_analysis["error"] == true {
|
|
269
|
+
risks := push_unique_text(risks, "Diff content analysis failed — purpose and content-based risk hints may be incomplete")
|
|
270
|
+
} else if diff_analysis["truncated"] == true {
|
|
271
|
+
risks := push_unique_text(risks, "Diff analysis was truncated at " + to_string(diff_analysis["max_bytes"]) + " bytes — purpose and content-based risk hints may be incomplete")
|
|
272
|
+
}
|
|
273
|
+
commits := recent_commits(5)
|
|
274
|
+
# Build file details array
|
|
275
|
+
file_details := []
|
|
276
|
+
fi_idx := 0
|
|
277
|
+
while fi_idx < len(files) {
|
|
278
|
+
f := to_string(files[fi_idx])
|
|
279
|
+
lang := lang_for_file(f)
|
|
280
|
+
entry := {
|
|
281
|
+
"path": f,
|
|
282
|
+
"language": lang
|
|
283
|
+
}
|
|
284
|
+
file_details := push(file_details, entry)
|
|
285
|
+
fi_idx := fi_idx + 1
|
|
286
|
+
}
|
|
287
|
+
output := {
|
|
288
|
+
"tool": "patchbrief",
|
|
289
|
+
"version": "1.0.1",
|
|
290
|
+
"repo": repo,
|
|
291
|
+
"branch": branch,
|
|
292
|
+
"summary": {
|
|
293
|
+
"files_changed": len(files),
|
|
294
|
+
"lines_added": stat["added"],
|
|
295
|
+
"lines_removed": stat["removed"]
|
|
296
|
+
},
|
|
297
|
+
"analysis": {
|
|
298
|
+
"diff_bytes_analyzed": diff_analysis["bytes_analyzed"],
|
|
299
|
+
"diff_error": diff_analysis["error"],
|
|
300
|
+
"diff_max_bytes": diff_analysis["max_bytes"],
|
|
301
|
+
"diff_truncated": diff_analysis["truncated"]
|
|
302
|
+
},
|
|
303
|
+
"likely_purpose": purpose,
|
|
304
|
+
"files": file_details,
|
|
305
|
+
"risk_areas": risks,
|
|
306
|
+
"recent_commits": commits
|
|
307
|
+
}
|
|
308
|
+
if pretty_json == true { print(to_json_pretty(output)) } else { print(to_json(output)) }
|
|
309
|
+
}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"bundleVersion": "0.1.0",
|
|
4
|
+
"runtime": {
|
|
5
|
+
"minimumVersion": "1.2.0"
|
|
6
|
+
},
|
|
7
|
+
"components": [
|
|
8
|
+
{
|
|
9
|
+
"id": "changebucket",
|
|
10
|
+
"repository": "https://github.com/kujolang/changebucket",
|
|
11
|
+
"gitCommit": "6fcaf41e7ca6c317ebb3b3408b4d185e76fb1640",
|
|
12
|
+
"version": "1.0.0",
|
|
13
|
+
"license": "MIT",
|
|
14
|
+
"entrypoint": "changebucket.kujo",
|
|
15
|
+
"files": [
|
|
16
|
+
"LICENSE",
|
|
17
|
+
"changebucket.kujo",
|
|
18
|
+
"src/cli.kujo",
|
|
19
|
+
"src/analyze.kujo",
|
|
20
|
+
"src/budget.kujo",
|
|
21
|
+
"src/classify.kujo",
|
|
22
|
+
"src/diffsrc.kujo",
|
|
23
|
+
"src/render.kujo",
|
|
24
|
+
"src/util.kujo"
|
|
25
|
+
],
|
|
26
|
+
"checksums": {
|
|
27
|
+
"LICENSE": "4b6449939f8dce26dc5fb87756740a5977da9085517af127d9e634e6a6492506",
|
|
28
|
+
"changebucket.kujo": "74613364f008c52238aaeb89db99076229bca83a1e9ace50ee2b7037f179a9fd",
|
|
29
|
+
"src/cli.kujo": "221b482606be0620021ffe1ce7d0bf7109feb7425aff3c0548d0d09f21779b48",
|
|
30
|
+
"src/analyze.kujo": "17924d0133926622ac5b2a7f0d34971fd8e758e590ab067be444816864d1eafc",
|
|
31
|
+
"src/budget.kujo": "7e253ca9ee4a36e42aebf79f8af9b3af5bd3b251e8d0a44d674b5058ce347bde",
|
|
32
|
+
"src/classify.kujo": "4a79df8bc7db71bcc0805b76a37a6f77935c6db40795382db852dc0622ba7ed5",
|
|
33
|
+
"src/diffsrc.kujo": "9eb254c59ebeb6283bb88cd9b69a2059563a7f9ef0f7fe6bf22cbbc1bba94cd8",
|
|
34
|
+
"src/render.kujo": "60b084134fca588640a8bd02b9e2397d3a586b94ba5a2cb48bc4d7d1bc9850ac",
|
|
35
|
+
"src/util.kujo": "6bffc05e1dd0918e3934d6dd43681f326dae85ab9cb4f06adb24c08822e050ad"
|
|
36
|
+
},
|
|
37
|
+
"outputContracts": [
|
|
38
|
+
{
|
|
39
|
+
"name": "analysis",
|
|
40
|
+
"format": "json",
|
|
41
|
+
"schema": "schemas/changebucket-analysis.schema.json"
|
|
42
|
+
}
|
|
43
|
+
]
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
"id": "patchbrief",
|
|
47
|
+
"repository": "https://github.com/kujolang/patchbrief",
|
|
48
|
+
"gitCommit": "d88397da0d98825191a76fdbce7a68fb9acb9a55",
|
|
49
|
+
"version": "1.0.1",
|
|
50
|
+
"license": "MIT",
|
|
51
|
+
"entrypoint": "patchbrief.kujo",
|
|
52
|
+
"files": [
|
|
53
|
+
"LICENSE",
|
|
54
|
+
"patchbrief.kujo",
|
|
55
|
+
"src/common.kujo",
|
|
56
|
+
"src/git.kujo",
|
|
57
|
+
"src/summarize.kujo",
|
|
58
|
+
"src/suggest_tests.kujo",
|
|
59
|
+
"src/handoff.kujo",
|
|
60
|
+
"schemas/patchbrief-summary.schema.json",
|
|
61
|
+
"schemas/patchbrief-handoff.schema.json"
|
|
62
|
+
],
|
|
63
|
+
"checksums": {
|
|
64
|
+
"LICENSE": "4b6449939f8dce26dc5fb87756740a5977da9085517af127d9e634e6a6492506",
|
|
65
|
+
"patchbrief.kujo": "510e7880c9002fa0d630f0377440803b2b1dfb9f818633eb47d1daf058521645",
|
|
66
|
+
"src/common.kujo": "8fbd7f7853ae47f5f726cae3131cc27ffc21c3052b7740c85d057e382811f133",
|
|
67
|
+
"src/git.kujo": "4611fb50e827ec74abd26b607a91d5ec8a48a7bbb99900af9496b1e972582622",
|
|
68
|
+
"src/summarize.kujo": "55e62d1aa58fd724cbd7c4686f7da15a33b83116d01cb2810d1509b98dfe2c1e",
|
|
69
|
+
"src/suggest_tests.kujo": "667be110291da1d0c86015a51298cf2c93e3f7402997b1094803b6d80114286c",
|
|
70
|
+
"src/handoff.kujo": "74ad797e6c554f62a7c0cc1a7633f5d4097fea0d8c73ab412c2b44e3ab462810",
|
|
71
|
+
"schemas/patchbrief-summary.schema.json": "0fb7277cae93f93285bc69481c58edf3fe8590f6bd5960241b3ca3d6fa1f19bf",
|
|
72
|
+
"schemas/patchbrief-handoff.schema.json": "314416c21471023087309b46d783997399bb552ace95f80796a955256a58d0ed"
|
|
73
|
+
},
|
|
74
|
+
"outputContracts": [
|
|
75
|
+
{
|
|
76
|
+
"name": "summary",
|
|
77
|
+
"format": "json",
|
|
78
|
+
"schema": "schemas/patchbrief-summary.schema.json"
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
"name": "handoff",
|
|
82
|
+
"format": "json",
|
|
83
|
+
"schema": "schemas/patchbrief-handoff.schema.json"
|
|
84
|
+
}
|
|
85
|
+
]
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
"id": "failure-evidence",
|
|
89
|
+
"repository": "https://github.com/kujolang/casefile",
|
|
90
|
+
"gitCommit": "6e8a6ded379a9882b2e48b0a8f0bad57e284c3bf",
|
|
91
|
+
"version": "1.0.0",
|
|
92
|
+
"license": "MIT",
|
|
93
|
+
"entrypoint": "casefile.kujo",
|
|
94
|
+
"files": [
|
|
95
|
+
"LICENSE",
|
|
96
|
+
"casefile.kujo"
|
|
97
|
+
],
|
|
98
|
+
"checksums": {
|
|
99
|
+
"LICENSE": "4b6449939f8dce26dc5fb87756740a5977da9085517af127d9e634e6a6492506",
|
|
100
|
+
"casefile.kujo": "28ffc48f61b9abc959f590ef33ad0e75c060fd825801e46f943139050bbf9a2d"
|
|
101
|
+
},
|
|
102
|
+
"outputContracts": [
|
|
103
|
+
{
|
|
104
|
+
"name": "case",
|
|
105
|
+
"format": "json",
|
|
106
|
+
"schema": "schemas/failure-evidence.schema.json"
|
|
107
|
+
}
|
|
108
|
+
]
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
"id": "context",
|
|
112
|
+
"repository": "https://github.com/kujolang/scent",
|
|
113
|
+
"gitCommit": "6e72cd06bf422a29e93148cf4edaddd98d937392",
|
|
114
|
+
"version": "1.0.0",
|
|
115
|
+
"license": "MIT",
|
|
116
|
+
"entrypoint": "scent.kujo",
|
|
117
|
+
"files": [
|
|
118
|
+
"LICENSE",
|
|
119
|
+
"scent.kujo"
|
|
120
|
+
],
|
|
121
|
+
"checksums": {
|
|
122
|
+
"LICENSE": "4b6449939f8dce26dc5fb87756740a5977da9085517af127d9e634e6a6492506",
|
|
123
|
+
"scent.kujo": "01c16d6dfe3db280c5fc9a0ab689dc6de288f749daac17c9acadbb898f174f98"
|
|
124
|
+
},
|
|
125
|
+
"outputContracts": [
|
|
126
|
+
{
|
|
127
|
+
"name": "context",
|
|
128
|
+
"format": "json",
|
|
129
|
+
"schema": "schemas/context-pack.schema.json"
|
|
130
|
+
}
|
|
131
|
+
]
|
|
132
|
+
}
|
|
133
|
+
]
|
|
134
|
+
}
|