@plumpslabs/kuma 2.4.20 β 2.4.22
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/dist/index.js +76 -35
- package/package.json +1 -1
- package/plugin.json +1 -1
- package/skills/kuma/SKILL.md +72 -0
package/dist/index.js
CHANGED
|
@@ -11438,30 +11438,33 @@ function opencodePluginTemplate() {
|
|
|
11438
11438
|
" }",
|
|
11439
11439
|
"}",
|
|
11440
11440
|
"",
|
|
11441
|
+
"function enforceGotchas(tool, args) {",
|
|
11442
|
+
' const name = String(tool || "").toLowerCase();',
|
|
11443
|
+
" const argv = args || {};",
|
|
11444
|
+
' const targetPath = argv.filePath || argv.targetFile || argv.path || argv.file || "";',
|
|
11445
|
+
" if (!targetPath) return;",
|
|
11446
|
+
' if (!(name.includes("edit") || name.includes("write") || name.includes("patch"))) return;',
|
|
11447
|
+
" const blocking = getBlockingGotchasForFile(String(targetPath));",
|
|
11448
|
+
" if (blocking.length > 0) {",
|
|
11449
|
+
" throw new Error(",
|
|
11450
|
+
" `\u{1F43B} [Kuma] ${blocking.length} critical/high gotcha(s) for ${targetPath}:\\n` +",
|
|
11451
|
+
' blocking.map((g) => ` \u{1F534} ${g}`).join("\\n") +',
|
|
11452
|
+
' `\\nRead .kuma/KNOWN_GOTCHAS.md for workarounds, or run kuma_memory({ action: "gotcha" }) to list.`',
|
|
11453
|
+
" );",
|
|
11454
|
+
" }",
|
|
11455
|
+
"}",
|
|
11456
|
+
"",
|
|
11457
|
+
"// \u2500\u2500\u2500 v1 host: factory (named export, legacy mode requires functions) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500",
|
|
11441
11458
|
"export const KumaPlugin = async () => {",
|
|
11442
11459
|
" return {",
|
|
11443
11460
|
' "tool.execute.before": async (input, output) => {',
|
|
11444
|
-
|
|
11445
|
-
" const args = output.args || {};",
|
|
11446
|
-
' const targetPath = args.filePath || args.targetFile || args.path || args.file || "";',
|
|
11447
|
-
" if (!targetPath) return;",
|
|
11448
|
-
' if (!(tool.includes("edit") || tool.includes("write") || tool.includes("patch"))) return;',
|
|
11449
|
-
" const blocking = getBlockingGotchasForFile(String(targetPath));",
|
|
11450
|
-
" if (blocking.length > 0) {",
|
|
11451
|
-
" throw new Error(",
|
|
11452
|
-
" `\u{1F43B} [Kuma] ${blocking.length} critical/high gotcha(s) for ${targetPath}:\\n` +",
|
|
11453
|
-
' blocking.map((g) => ` \u{1F534} ${g}`).join("\\n") +',
|
|
11454
|
-
' `\\nRead .kuma/KNOWN_GOTCHAS.md for workarounds, or run kuma_memory({ action: "gotcha" }) to list.`',
|
|
11455
|
-
" );",
|
|
11456
|
-
" }",
|
|
11461
|
+
" enforceGotchas(input?.tool, output?.args);",
|
|
11457
11462
|
" },",
|
|
11458
11463
|
' "file.edited": async (input) => {',
|
|
11459
|
-
|
|
11460
|
-
' const fp = input.filePath || input.path || (input.file && input.file.path) || "";',
|
|
11464
|
+
' const fp = input?.filePath || input?.path || (input?.file && input?.file.path) || "";',
|
|
11461
11465
|
' if (fp) console.warn(`\u{1F43B} [Kuma] ${fp} edited \u2014 consider kuma_safety({ action: "verify", scope: "${fp}" })`);',
|
|
11462
11466
|
" },",
|
|
11463
11467
|
' "experimental.session.compacting": async (input, output) => {',
|
|
11464
|
-
" // Compaction survival set via the native channel (docs: plugins#compaction).",
|
|
11465
11468
|
" try {",
|
|
11466
11469
|
' const { execSync } = await import("node:child_process");',
|
|
11467
11470
|
' const ctx = execSync("kuma hook pre-compact", { encoding: "utf-8", timeout: 8000 });',
|
|
@@ -11473,28 +11476,46 @@ function opencodePluginTemplate() {
|
|
|
11473
11476
|
" };",
|
|
11474
11477
|
"};",
|
|
11475
11478
|
"",
|
|
11476
|
-
"//
|
|
11477
|
-
"
|
|
11478
|
-
"
|
|
11479
|
-
'
|
|
11480
|
-
"
|
|
11481
|
-
|
|
11482
|
-
"
|
|
11483
|
-
'
|
|
11484
|
-
|
|
11485
|
-
|
|
11486
|
-
"
|
|
11487
|
-
|
|
11488
|
-
|
|
11489
|
-
'
|
|
11490
|
-
"
|
|
11491
|
-
"
|
|
11479
|
+
"// \u2500\u2500\u2500 v1 host: module object form (v1 >= 1.18 calls server(), ignores setup) \u2500",
|
|
11480
|
+
"async function server() {",
|
|
11481
|
+
" return {",
|
|
11482
|
+
' "tool.execute.before": async (input, output) => {',
|
|
11483
|
+
" enforceGotchas(input?.tool, output?.args);",
|
|
11484
|
+
" },",
|
|
11485
|
+
' "file.edited": async (input) => {',
|
|
11486
|
+
' const fp = input?.filePath || input?.path || (input?.file && input?.file.path) || "";',
|
|
11487
|
+
' if (fp) console.warn(`\u{1F43B} [Kuma] ${fp} edited \u2014 consider kuma_safety({ action: "verify", scope: "${fp}" })`);',
|
|
11488
|
+
" },",
|
|
11489
|
+
' "experimental.session.compacting": async (input, output) => {',
|
|
11490
|
+
" try {",
|
|
11491
|
+
' const { execSync } = await import("node:child_process");',
|
|
11492
|
+
' const ctx = execSync("kuma hook pre-compact", { encoding: "utf-8", timeout: 8000 });',
|
|
11493
|
+
' const parsed = JSON.parse(ctx || "{}");',
|
|
11494
|
+
' const add = parsed?.hookSpecificOutput?.hookSpecificOutput?.additionalContext || "";',
|
|
11495
|
+
" if (add && output && Array.isArray(output.context)) output.context.push(add);",
|
|
11496
|
+
" } catch { /* compacting must never fail */ }",
|
|
11497
|
+
" },",
|
|
11498
|
+
" };",
|
|
11499
|
+
"}",
|
|
11500
|
+
"",
|
|
11501
|
+
"// \u2500\u2500\u2500 v2 host: setup registers hooks on ctx (mutable event draft) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500",
|
|
11502
|
+
"async function setup(ctx) {",
|
|
11503
|
+
' const hook = ctx && ctx.tool && typeof ctx.tool.hook === "function"',
|
|
11504
|
+
" ? ctx.tool.hook.bind(ctx.tool)",
|
|
11505
|
+
" : null;",
|
|
11506
|
+
" if (!hook) return;",
|
|
11507
|
+
' await hook("execute.before", async (event) => {',
|
|
11508
|
+
" const e = event || {};",
|
|
11509
|
+
' const tool = e.tool ?? e.toolName ?? e.name ?? e.input?.tool ?? "";',
|
|
11510
|
+
" const args = e.input ?? e.args ?? e.output?.args ?? {};",
|
|
11511
|
+
" enforceGotchas(tool, args);",
|
|
11512
|
+
" });",
|
|
11513
|
+
"}",
|
|
11492
11514
|
"",
|
|
11493
11515
|
"export default {",
|
|
11494
11516
|
' id: "kuma",',
|
|
11495
|
-
"
|
|
11496
|
-
"
|
|
11497
|
-
" setup: () => kumaHooks,",
|
|
11517
|
+
" server,",
|
|
11518
|
+
" setup,",
|
|
11498
11519
|
"};",
|
|
11499
11520
|
""
|
|
11500
11521
|
].join("\n");
|
|
@@ -13836,6 +13857,7 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
|
13836
13857
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
13837
13858
|
|
|
13838
13859
|
// src/manifest.ts
|
|
13860
|
+
import { ListToolsRequestSchema } from "@modelcontextprotocol/sdk/types.js";
|
|
13839
13861
|
import { z } from "zod";
|
|
13840
13862
|
|
|
13841
13863
|
// src/tools/kumaContextTool.ts
|
|
@@ -15618,6 +15640,25 @@ function registerAllTools(server) {
|
|
|
15618
15640
|
server.tool("kuma_kuma_safety", safetyDesc, safetySchema, safetyHandler);
|
|
15619
15641
|
console.error("[Manifest] Registered 3 core tools with universal dual-prefix aliases (kuma_* and kuma_kuma_*).");
|
|
15620
15642
|
console.error("[Manifest] Auto-init hooks installed on all tools.");
|
|
15643
|
+
const baseServer = server.server;
|
|
15644
|
+
const existingListHandler = baseServer._requestHandlers?.get("tools/list");
|
|
15645
|
+
if (existingListHandler) {
|
|
15646
|
+
const stripSchemaMeta = (schema) => {
|
|
15647
|
+
if (!schema || typeof schema !== "object") return;
|
|
15648
|
+
for (const key of ["$schema", "$id", "id", "title", "definitions", "$defs"]) {
|
|
15649
|
+
delete schema[key];
|
|
15650
|
+
}
|
|
15651
|
+
};
|
|
15652
|
+
baseServer.removeRequestHandler("tools/list");
|
|
15653
|
+
baseServer.setRequestHandler(ListToolsRequestSchema, async (request, extra) => {
|
|
15654
|
+
const result = await existingListHandler(request, extra);
|
|
15655
|
+
for (const tool of result?.tools ?? []) {
|
|
15656
|
+
stripSchemaMeta(tool.inputSchema);
|
|
15657
|
+
stripSchemaMeta(tool.outputSchema);
|
|
15658
|
+
}
|
|
15659
|
+
return result;
|
|
15660
|
+
});
|
|
15661
|
+
}
|
|
15621
15662
|
}
|
|
15622
15663
|
|
|
15623
15664
|
// src/index.ts
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@plumpslabs/kuma",
|
|
3
|
-
"version": "2.4.
|
|
3
|
+
"version": "2.4.22",
|
|
4
4
|
"description": "Safety-first context & orchestration engine for AI coding agents. MCP server with mandatory research pipeline, knowledge graph, impact analysis, decision memory, and safety guard β works with any MCP client.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
package/plugin.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://antigravity.google/schemas/v1/plugin.json",
|
|
3
3
|
"name": "kuma",
|
|
4
|
-
"version": "2.4.
|
|
4
|
+
"version": "2.4.22",
|
|
5
5
|
"description": "Safety-first context & orchestration engine for AI coding agents. Shadow memory, gotcha lifecycle, blast radius impact analysis, and test verification.",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "plumpslabs",
|
package/skills/kuma/SKILL.md
CHANGED
|
@@ -100,5 +100,77 @@ Record what matters, skip what doesn't.
|
|
|
100
100
|
|
|
101
101
|
π Full rules: `.kuma/init.md`
|
|
102
102
|
|
|
103
|
+
π Read `.kuma/init.md` for detailed rules.
|
|
104
|
+
π Readable state: `.kuma/KNOWN_GOTCHAS.md` (gotchas) Β· `.kuma/memories/decisions.md` (decisions)
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
_Generated by Kuma MCP - https://github.com/plumpslabs/kuma_
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
name: kuma-mcp
|
|
111
|
+
description: Kuma MCP β .kuma/ is the single source of truth
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
Kuma MCP tools: kuma_context, kuma_memory, kuma_safety.
|
|
115
|
+
Record what matters, skip what doesn't.
|
|
116
|
+
|
|
117
|
+
<kuma_obedience>
|
|
118
|
+
## π Obedience β honest model (issue #39)
|
|
119
|
+
- HARNESS-ENFORCED (no choice): MCP schema rejects unknown actions; hooks inject gotchas pre-edit (`kuma hook pre-edit`); SessionStart serves the brief; dirty-flags patch the map post-edit.
|
|
120
|
+
- AGENT-EXPECTED (best-effort ~70%): call `kuma_context({ action: "init" })` first; record gotchas IMMEDIATELY; `kuma_safety({ action: "verify" })` after edits.
|
|
121
|
+
- FALLBACKS: init skipped β lazy brief on first unfamiliar edit; gotcha skipped β auto-gotcha on repeated failures; verify skipped β CI is the backstop (never treat as verified).
|
|
122
|
+
</kuma_obedience>
|
|
123
|
+
|
|
124
|
+
<kuma_workflow>
|
|
125
|
+
π§ **Before coding:** `kuma_context({ action: "init" })`
|
|
126
|
+
πΊοΈ **Monorepo map:** `kuma_context({ action: "map" })`
|
|
127
|
+
π¬ **Unfamiliar code / blast radius:** `kuma_context({ action: "research", scope: "<area>" })` or `kuma_context({ action: "impact", target: "<file>" })`
|
|
128
|
+
π **Found a bug/quirk:** `kuma_memory({ action: "gotcha" })` (IMMEDIATELY)
|
|
129
|
+
π§ **Chose between options:** `kuma_memory({ action: "decision" })`
|
|
130
|
+
π **Traced a flow:** `kuma_memory({ action: "arch_flow" })` (max 5 files)
|
|
131
|
+
π‘οΈ **Before risky work / after edits:** `kuma_safety({ action: "guard" | "verify" })`
|
|
132
|
+
</kuma_workflow>
|
|
133
|
+
|
|
134
|
+
πͺ **Auto-inject (Claude Code):** gotcha/decision/history injected automatically before edits
|
|
135
|
+
via the PreToolUse hook β an empty hook output means the file has no gotchas.
|
|
136
|
+
|
|
137
|
+
π Full rules: `.kuma/init.md`
|
|
138
|
+
|
|
139
|
+
π Read `.kuma/init.md` for detailed rules.
|
|
140
|
+
π Readable state: `.kuma/KNOWN_GOTCHAS.md` (gotchas) Β· `.kuma/memories/decisions.md` (decisions)
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
_Generated by Kuma MCP - https://github.com/plumpslabs/kuma_
|
|
144
|
+
|
|
145
|
+
---
|
|
146
|
+
name: kuma-mcp
|
|
147
|
+
description: Kuma MCP β .kuma/ is the single source of truth
|
|
148
|
+
---
|
|
149
|
+
|
|
150
|
+
Kuma MCP tools: kuma_context, kuma_memory, kuma_safety.
|
|
151
|
+
Record what matters, skip what doesn't.
|
|
152
|
+
|
|
153
|
+
<kuma_obedience>
|
|
154
|
+
## π Obedience β honest model (issue #39)
|
|
155
|
+
- HARNESS-ENFORCED (no choice): MCP schema rejects unknown actions; hooks inject gotchas pre-edit (`kuma hook pre-edit`); SessionStart serves the brief; dirty-flags patch the map post-edit.
|
|
156
|
+
- AGENT-EXPECTED (best-effort ~70%): call `kuma_context({ action: "init" })` first; record gotchas IMMEDIATELY; `kuma_safety({ action: "verify" })` after edits.
|
|
157
|
+
- FALLBACKS: init skipped β lazy brief on first unfamiliar edit; gotcha skipped β auto-gotcha on repeated failures; verify skipped β CI is the backstop (never treat as verified).
|
|
158
|
+
</kuma_obedience>
|
|
159
|
+
|
|
160
|
+
<kuma_workflow>
|
|
161
|
+
π§ **Before coding:** `kuma_context({ action: "init" })`
|
|
162
|
+
πΊοΈ **Monorepo map:** `kuma_context({ action: "map" })`
|
|
163
|
+
π¬ **Unfamiliar code / blast radius:** `kuma_context({ action: "research", scope: "<area>" })` or `kuma_context({ action: "impact", target: "<file>" })`
|
|
164
|
+
π **Found a bug/quirk:** `kuma_memory({ action: "gotcha" })` (IMMEDIATELY)
|
|
165
|
+
π§ **Chose between options:** `kuma_memory({ action: "decision" })`
|
|
166
|
+
π **Traced a flow:** `kuma_memory({ action: "arch_flow" })` (max 5 files)
|
|
167
|
+
π‘οΈ **Before risky work / after edits:** `kuma_safety({ action: "guard" | "verify" })`
|
|
168
|
+
</kuma_workflow>
|
|
169
|
+
|
|
170
|
+
πͺ **Auto-inject (Claude Code):** gotcha/decision/history injected automatically before edits
|
|
171
|
+
via the PreToolUse hook β an empty hook output means the file has no gotchas.
|
|
172
|
+
|
|
173
|
+
π Full rules: `.kuma/init.md`
|
|
174
|
+
|
|
103
175
|
π Read `.kuma/init.md` for detailed rules.
|
|
104
176
|
π Readable state: `.kuma/KNOWN_GOTCHAS.md` (gotchas) Β· `.kuma/memories/decisions.md` (decisions)
|