@plumpslabs/kuma 2.3.6 → 2.3.8

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,177 @@
1
+ import {
2
+ getActiveGotchas
3
+ } from "./chunk-53J56QCQ.js";
4
+ import {
5
+ sessionMemory
6
+ } from "./chunk-SLRRDKQ2.js";
7
+ import {
8
+ getDb
9
+ } from "./chunk-NAM7SCBT.js";
10
+ import {
11
+ getProjectRoot
12
+ } from "./chunk-E2KFPEBT.js";
13
+
14
+ // src/engine/contextDigest.ts
15
+ import fs from "fs";
16
+ import path from "path";
17
+ function detectTechStack() {
18
+ const root = getProjectRoot();
19
+ const stack = {
20
+ languages: [],
21
+ framework: null,
22
+ database: null,
23
+ testRunner: null,
24
+ packageManager: null,
25
+ monorepo: false
26
+ };
27
+ try {
28
+ const pkgPath = path.join(root, "package.json");
29
+ if (fs.existsSync(pkgPath)) {
30
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf-8"));
31
+ const deps = { ...pkg.dependencies, ...pkg.devDependencies };
32
+ if (fs.existsSync(path.join(root, "pnpm-lock.yaml"))) stack.packageManager = "pnpm";
33
+ else if (fs.existsSync(path.join(root, "yarn.lock"))) stack.packageManager = "yarn";
34
+ else stack.packageManager = "npm";
35
+ stack.monorepo = !!pkg.workspaces;
36
+ if (deps.next) stack.framework = "Next.js";
37
+ else if (deps.react) stack.framework = "React";
38
+ else if (deps.vue) stack.framework = "Vue";
39
+ else if (deps.express) stack.framework = "Express";
40
+ else if (deps.fastify) stack.framework = "Fastify";
41
+ else if (deps.nest) stack.framework = "NestJS";
42
+ else if (deps["@remix-run/react"]) stack.framework = "Remix";
43
+ else if (deps.svelte) stack.framework = "Svelte";
44
+ else if (deps.angular) stack.framework = "Angular";
45
+ if (deps.prisma) stack.database = "Prisma";
46
+ else if (deps.typeorm) stack.database = "TypeORM";
47
+ else if (deps.mongoose) stack.database = "MongoDB";
48
+ else if (deps.pg || deps["@neondatabase/serverless"]) stack.database = "PostgreSQL";
49
+ else if (deps.redis) stack.database = "Redis";
50
+ else if (deps.better || deps.drizzle) stack.database = "Drizzle";
51
+ if (deps.jest || deps["@jest/core"]) stack.testRunner = "Jest";
52
+ else if (deps.vitest) stack.testRunner = "Vitest";
53
+ else if (deps.mocha) stack.testRunner = "Mocha";
54
+ else if (deps.playwright) stack.testRunner = "Playwright";
55
+ else if (deps.cypress) stack.testRunner = "Cypress";
56
+ if (fs.existsSync(path.join(root, "tsconfig.json"))) stack.languages.push("TypeScript");
57
+ if (deps.typescript) stack.languages.push("TypeScript");
58
+ if (fs.existsSync(path.join(root, "jsconfig.json"))) stack.languages.push("JavaScript");
59
+ if (fs.existsSync(path.join(root, "go.mod"))) stack.languages.push("Go");
60
+ if (fs.existsSync(path.join(root, "Cargo.toml"))) stack.languages.push("Rust");
61
+ if (fs.existsSync(path.join(root, "pyproject.toml"))) stack.languages.push("Python");
62
+ if (fs.existsSync(path.join(root, "Gemfile"))) stack.languages.push("Ruby");
63
+ if (stack.languages.length === 0) stack.languages.push("JavaScript");
64
+ }
65
+ } catch {
66
+ }
67
+ return stack;
68
+ }
69
+ function detectEntryPoints() {
70
+ const root = getProjectRoot();
71
+ const entryPoints = [];
72
+ const candidates = [
73
+ "src/index.ts",
74
+ "src/index.js",
75
+ "src/app.ts",
76
+ "src/app.js",
77
+ "index.ts",
78
+ "index.js",
79
+ "src/main.ts",
80
+ "src/main.js",
81
+ "src/server.ts",
82
+ "src/server.js",
83
+ "app.ts",
84
+ "app.js",
85
+ "pages/index.tsx",
86
+ "pages/index.jsx",
87
+ "src/App.tsx",
88
+ "src/App.js",
89
+ "lib/main.ts",
90
+ "lib/index.ts"
91
+ ];
92
+ for (const c of candidates) {
93
+ if (fs.existsSync(path.join(root, c))) {
94
+ entryPoints.push(c);
95
+ }
96
+ }
97
+ try {
98
+ const pkg = JSON.parse(fs.readFileSync(path.join(root, "package.json"), "utf-8"));
99
+ if (pkg.main && fs.existsSync(path.join(root, pkg.main))) {
100
+ if (!entryPoints.includes(pkg.main)) entryPoints.push(pkg.main);
101
+ }
102
+ } catch {
103
+ }
104
+ return entryPoints;
105
+ }
106
+ async function getActiveADRs() {
107
+ try {
108
+ const db = await getDb();
109
+ const stmt = db.prepare(
110
+ "SELECT title FROM decision_log WHERE status = 'active' ORDER BY created_at DESC LIMIT 5"
111
+ );
112
+ const results = [];
113
+ while (stmt.step()) {
114
+ const row = stmt.getAsObject();
115
+ results.push(row.title);
116
+ }
117
+ stmt.free();
118
+ return results;
119
+ } catch {
120
+ return [];
121
+ }
122
+ }
123
+ async function generateContextDigest() {
124
+ const stack = detectTechStack();
125
+ const entryPoints = detectEntryPoints();
126
+ const adrs = await getActiveADRs();
127
+ const gotchas = getActiveGotchas();
128
+ const summary = sessionMemory.getSummary();
129
+ const lines = [
130
+ "\u{1F4CB} **Kuma Digest** \u2014 <500 token briefing",
131
+ "\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501",
132
+ ""
133
+ ];
134
+ const langStr = stack.languages.join("/");
135
+ const frameworkStr = stack.framework || "\u2014";
136
+ const dbStr = stack.database || "\u2014";
137
+ const testStr = stack.testRunner || "\u2014";
138
+ const pmStr = stack.packageManager || "\u2014";
139
+ lines.push(`\u{1F527} **Stack**: ${langStr} | ${frameworkStr} | ${dbStr} | ${testStr} | ${pmStr}${stack.monorepo ? " (monorepo)" : ""}`);
140
+ lines.push(`\u{1F4C1} **Root**: ${getProjectRoot().split("/").pop() || "?"}`);
141
+ if (entryPoints.length > 0) {
142
+ lines.push(`\u{1F6AA} **Entry**: ${entryPoints.slice(0, 3).join(", ")}`);
143
+ }
144
+ try {
145
+ const ruleFile = path.join(getProjectRoot(), ".kuma", "DOMAIN_RULES.md");
146
+ if (fs.existsSync(ruleFile)) {
147
+ const content = fs.readFileSync(ruleFile, "utf-8");
148
+ const rules = content.split("\n").filter((l) => /^- Rule \d+:?\s*/i.test(l)).map((l) => l.replace(/^- Rule \d+:?\s*/i, "").trim()).filter(Boolean);
149
+ if (rules.length > 0) {
150
+ lines.push(`\u{1F4CB} **Rules**: ${rules.slice(0, 5).join(" | ")}`);
151
+ }
152
+ }
153
+ } catch {
154
+ }
155
+ if (gotchas.length > 0) {
156
+ const critical = gotchas.filter((g) => g.severity === "critical" || g.severity === "high");
157
+ if (critical.length > 0) {
158
+ lines.push(`\u26A0\uFE0F **Gotchas**: ${critical.length} high/critical \u2014 ${critical.slice(0, 3).map((g) => g.filePath).join(", ")}`);
159
+ } else {
160
+ lines.push(`\u26A0\uFE0F **Gotchas**: ${gotchas.length} recorded`);
161
+ }
162
+ }
163
+ if (adrs.length > 0) {
164
+ lines.push(`\u{1F4DD} **ADRs**: ${adrs.slice(0, 3).join(" | ")}`);
165
+ }
166
+ lines.push(`\u{1F3AF} **Goal**: ${summary.currentGoal?.substring(0, 80) || "not set"}`);
167
+ const text = lines.join("\n");
168
+ const estimatedTokens = Math.ceil(text.length / 4);
169
+ if (estimatedTokens > 450) {
170
+ lines.push(`\u{1F4CA} *~${estimatedTokens} tokens, fits under 500 limit*`);
171
+ }
172
+ return lines.join("\n") + "\n\n\u{1F4A1} Use kuma_context({ action: 'sync' }) for full state.";
173
+ }
174
+ export {
175
+ generateContextDigest,
176
+ generateContextDigest as generateDigest
177
+ };
@@ -0,0 +1,20 @@
1
+ import {
2
+ appendToLayer,
3
+ checkFileGotchas,
4
+ generateDigest,
5
+ getActiveGotchas,
6
+ getLayersSummary,
7
+ readLayer,
8
+ writeLayer
9
+ } from "./chunk-53J56QCQ.js";
10
+ import "./chunk-SLRRDKQ2.js";
11
+ import "./chunk-E2KFPEBT.js";
12
+ export {
13
+ appendToLayer,
14
+ checkFileGotchas,
15
+ generateDigest,
16
+ getActiveGotchas,
17
+ getLayersSummary,
18
+ readLayer,
19
+ writeLayer
20
+ };