@lakitu/sdk 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 (111) hide show
  1. package/README.md +166 -0
  2. package/convex/_generated/api.d.ts +45 -0
  3. package/convex/_generated/api.js +23 -0
  4. package/convex/_generated/dataModel.d.ts +58 -0
  5. package/convex/_generated/server.d.ts +143 -0
  6. package/convex/_generated/server.js +93 -0
  7. package/convex/cloud/CLAUDE.md +238 -0
  8. package/convex/cloud/_generated/api.ts +84 -0
  9. package/convex/cloud/_generated/component.ts +861 -0
  10. package/convex/cloud/_generated/dataModel.ts +60 -0
  11. package/convex/cloud/_generated/server.ts +156 -0
  12. package/convex/cloud/convex.config.ts +16 -0
  13. package/convex/cloud/index.ts +29 -0
  14. package/convex/cloud/intentSchema/generate.ts +447 -0
  15. package/convex/cloud/intentSchema/index.ts +16 -0
  16. package/convex/cloud/intentSchema/types.ts +418 -0
  17. package/convex/cloud/ksaPolicy.ts +554 -0
  18. package/convex/cloud/mail.ts +92 -0
  19. package/convex/cloud/schema.ts +322 -0
  20. package/convex/cloud/utils/kanbanContext.ts +229 -0
  21. package/convex/cloud/workflows/agentBoard.ts +451 -0
  22. package/convex/cloud/workflows/agentPrompt.ts +272 -0
  23. package/convex/cloud/workflows/agentThread.ts +374 -0
  24. package/convex/cloud/workflows/compileSandbox.ts +146 -0
  25. package/convex/cloud/workflows/crudBoard.ts +217 -0
  26. package/convex/cloud/workflows/crudKSAs.ts +262 -0
  27. package/convex/cloud/workflows/crudLorobeads.ts +371 -0
  28. package/convex/cloud/workflows/crudSkills.ts +205 -0
  29. package/convex/cloud/workflows/crudThreads.ts +708 -0
  30. package/convex/cloud/workflows/lifecycleSandbox.ts +1396 -0
  31. package/convex/cloud/workflows/sandboxConvex.ts +1046 -0
  32. package/convex/sandbox/README.md +90 -0
  33. package/convex/sandbox/_generated/api.d.ts +2934 -0
  34. package/convex/sandbox/_generated/api.js +23 -0
  35. package/convex/sandbox/_generated/dataModel.d.ts +60 -0
  36. package/convex/sandbox/_generated/server.d.ts +143 -0
  37. package/convex/sandbox/_generated/server.js +93 -0
  38. package/convex/sandbox/actions/bash.ts +130 -0
  39. package/convex/sandbox/actions/browser.ts +282 -0
  40. package/convex/sandbox/actions/file.ts +336 -0
  41. package/convex/sandbox/actions/lsp.ts +325 -0
  42. package/convex/sandbox/actions/pdf.ts +119 -0
  43. package/convex/sandbox/agent/codeExecLoop.ts +535 -0
  44. package/convex/sandbox/agent/decisions.ts +284 -0
  45. package/convex/sandbox/agent/index.ts +515 -0
  46. package/convex/sandbox/agent/subagents.ts +651 -0
  47. package/convex/sandbox/brandResearch/index.ts +417 -0
  48. package/convex/sandbox/context/index.ts +7 -0
  49. package/convex/sandbox/context/session.ts +402 -0
  50. package/convex/sandbox/convex.config.ts +17 -0
  51. package/convex/sandbox/index.ts +51 -0
  52. package/convex/sandbox/nodeActions/codeExec.ts +130 -0
  53. package/convex/sandbox/planning/beads.ts +187 -0
  54. package/convex/sandbox/planning/index.ts +8 -0
  55. package/convex/sandbox/planning/sync.ts +194 -0
  56. package/convex/sandbox/prompts/codeExec.ts +852 -0
  57. package/convex/sandbox/prompts/modes.ts +231 -0
  58. package/convex/sandbox/prompts/system.ts +142 -0
  59. package/convex/sandbox/schema.ts +510 -0
  60. package/convex/sandbox/state/artifacts.ts +99 -0
  61. package/convex/sandbox/state/checkpoints.ts +341 -0
  62. package/convex/sandbox/state/files.ts +383 -0
  63. package/convex/sandbox/state/index.ts +10 -0
  64. package/convex/sandbox/state/verification.actions.ts +268 -0
  65. package/convex/sandbox/state/verification.ts +101 -0
  66. package/convex/sandbox/tsconfig.json +25 -0
  67. package/convex/sandbox/utils/codeExecHelpers.ts +52 -0
  68. package/dist/cli/commands/build.d.ts +19 -0
  69. package/dist/cli/commands/build.d.ts.map +1 -0
  70. package/dist/cli/commands/build.js +223 -0
  71. package/dist/cli/commands/init.d.ts +16 -0
  72. package/dist/cli/commands/init.d.ts.map +1 -0
  73. package/dist/cli/commands/init.js +148 -0
  74. package/dist/cli/commands/publish.d.ts +12 -0
  75. package/dist/cli/commands/publish.d.ts.map +1 -0
  76. package/dist/cli/commands/publish.js +33 -0
  77. package/dist/cli/index.d.ts +14 -0
  78. package/dist/cli/index.d.ts.map +1 -0
  79. package/dist/cli/index.js +40 -0
  80. package/dist/sdk/builders.d.ts +104 -0
  81. package/dist/sdk/builders.d.ts.map +1 -0
  82. package/dist/sdk/builders.js +214 -0
  83. package/dist/sdk/index.d.ts +29 -0
  84. package/dist/sdk/index.d.ts.map +1 -0
  85. package/dist/sdk/index.js +38 -0
  86. package/dist/sdk/types.d.ts +107 -0
  87. package/dist/sdk/types.d.ts.map +1 -0
  88. package/dist/sdk/types.js +6 -0
  89. package/ksa/README.md +263 -0
  90. package/ksa/_generated/REFERENCE.md +2954 -0
  91. package/ksa/_generated/registry.ts +257 -0
  92. package/ksa/_shared/configReader.ts +302 -0
  93. package/ksa/_shared/configSchemas.ts +649 -0
  94. package/ksa/_shared/gateway.ts +175 -0
  95. package/ksa/_shared/ksaBehaviors.ts +411 -0
  96. package/ksa/_shared/ksaProxy.ts +248 -0
  97. package/ksa/_shared/localDb.ts +302 -0
  98. package/ksa/index.ts +134 -0
  99. package/package.json +93 -0
  100. package/runtime/browser/agent-browser.ts +330 -0
  101. package/runtime/entrypoint.ts +194 -0
  102. package/runtime/lsp/manager.ts +366 -0
  103. package/runtime/pdf/pdf-generator.ts +50 -0
  104. package/runtime/pdf/renderer.ts +357 -0
  105. package/runtime/pdf/schema.ts +97 -0
  106. package/runtime/services/file-watcher.ts +191 -0
  107. package/template/build.ts +307 -0
  108. package/template/e2b/Dockerfile +69 -0
  109. package/template/e2b/e2b.toml +13 -0
  110. package/template/e2b/prebuild.sh +68 -0
  111. package/template/e2b/start.sh +14 -0
@@ -0,0 +1,10 @@
1
+ /**
2
+ * State - File & Edit State Management
3
+ *
4
+ * Track file changes, edits, verification, and checkpoints.
5
+ */
6
+
7
+ export * as files from "./files";
8
+ export * as checkpoints from "./checkpoints";
9
+ export * as verification from "./verification";
10
+ export * as artifacts from "./artifacts";
@@ -0,0 +1,268 @@
1
+ "use node";
2
+
3
+ /**
4
+ * Verification Actions - Node.js Runtime
5
+ *
6
+ * Run tests and linters after edits to catch regressions early.
7
+ * Supports baseline comparisons and rollback on failure.
8
+ */
9
+
10
+ import { internalAction } from "../_generated/server";
11
+ import { v } from "convex/values";
12
+
13
+ // ============================================
14
+ // Types
15
+ // ============================================
16
+
17
+ interface VerificationResult {
18
+ success: boolean;
19
+ checks: Array<{
20
+ name: string;
21
+ success: boolean;
22
+ output?: string;
23
+ durationMs?: number;
24
+ }>;
25
+ }
26
+
27
+ interface TestSuiteResult {
28
+ success: boolean;
29
+ exitCode: number | null;
30
+ output?: string;
31
+ errors?: string;
32
+ durationMs: number;
33
+ timedOut?: boolean;
34
+ testCommand: string;
35
+ }
36
+
37
+ interface RegressionReport {
38
+ hasRegressions: boolean;
39
+ regressions: string[];
40
+ fixed: string[];
41
+ baselineFailureCount: number;
42
+ currentFailureCount: number;
43
+ }
44
+
45
+ // ============================================
46
+ // Actions (run actual verification)
47
+ // ============================================
48
+
49
+ /**
50
+ * Verify a file after edit (run linter/type checker)
51
+ */
52
+ export const verifyFile = internalAction({
53
+ args: {
54
+ path: v.string(),
55
+ cwd: v.optional(v.string()),
56
+ },
57
+ handler: async (ctx, args): Promise<VerificationResult> => {
58
+ const cwd = args.cwd || "/home/user/workspace";
59
+ const results: VerificationResult = {
60
+ success: true,
61
+ checks: [],
62
+ };
63
+
64
+ // Determine file type and run appropriate checks
65
+ const ext = args.path.split(".").pop()?.toLowerCase();
66
+
67
+ if (ext === "ts" || ext === "tsx") {
68
+ // Run TypeScript type check
69
+ const tscResult = await runCommand("bunx tsc --noEmit", cwd, 30000);
70
+ results.checks.push({
71
+ name: "typescript",
72
+ success: tscResult.exitCode === 0,
73
+ output: tscResult.stderr || tscResult.stdout,
74
+ durationMs: tscResult.durationMs,
75
+ });
76
+ if (tscResult.exitCode !== 0) results.success = false;
77
+ }
78
+
79
+ if (ext === "js" || ext === "jsx" || ext === "ts" || ext === "tsx") {
80
+ // Run ESLint
81
+ const eslintResult = await runCommand(
82
+ `bunx eslint "${args.path}" --format compact`,
83
+ cwd,
84
+ 15000
85
+ );
86
+ results.checks.push({
87
+ name: "eslint",
88
+ success: eslintResult.exitCode === 0,
89
+ output: eslintResult.stdout,
90
+ durationMs: eslintResult.durationMs,
91
+ });
92
+ // ESLint failures are warnings, not blockers
93
+ }
94
+
95
+ if (ext === "py") {
96
+ // Run Python type check
97
+ const mypyResult = await runCommand(`mypy "${args.path}"`, cwd, 30000);
98
+ results.checks.push({
99
+ name: "mypy",
100
+ success: mypyResult.exitCode === 0,
101
+ output: mypyResult.stdout,
102
+ durationMs: mypyResult.durationMs,
103
+ });
104
+ if (mypyResult.exitCode !== 0) results.success = false;
105
+ }
106
+
107
+ return results;
108
+ },
109
+ });
110
+
111
+ /**
112
+ * Run the test suite and detect regressions
113
+ */
114
+ export const runTestSuite = internalAction({
115
+ args: {
116
+ cwd: v.optional(v.string()),
117
+ testCommand: v.optional(v.string()),
118
+ timeoutMs: v.optional(v.number()),
119
+ },
120
+ handler: async (ctx, args): Promise<TestSuiteResult> => {
121
+ const cwd = args.cwd || "/home/user/workspace";
122
+ const testCommand = args.testCommand || detectTestCommand(cwd);
123
+ const timeoutMs = args.timeoutMs || 120000; // 2 minutes default
124
+
125
+ const result = await runCommand(testCommand, cwd, timeoutMs);
126
+
127
+ return {
128
+ success: result.exitCode === 0,
129
+ exitCode: result.exitCode,
130
+ output: result.stdout,
131
+ errors: result.stderr,
132
+ durationMs: result.durationMs,
133
+ timedOut: result.timedOut,
134
+ testCommand,
135
+ };
136
+ },
137
+ });
138
+
139
+ /**
140
+ * Compare test results to detect regressions
141
+ */
142
+ export const compareTestResults = internalAction({
143
+ args: {
144
+ baseline: v.any(), // TestSuiteResult
145
+ current: v.any(), // TestSuiteResult
146
+ },
147
+ handler: async (ctx, args): Promise<RegressionReport> => {
148
+ const baseline = args.baseline as TestSuiteResult;
149
+ const current = args.current as TestSuiteResult;
150
+
151
+ // Parse test output to extract failure names
152
+ const baselineFailures = parseTestFailures(baseline.output || "");
153
+ const currentFailures = parseTestFailures(current.output || "");
154
+
155
+ // Find new failures (regressions)
156
+ const regressions = currentFailures.filter(
157
+ (f) => !baselineFailures.includes(f)
158
+ );
159
+
160
+ // Find fixed tests
161
+ const fixed = baselineFailures.filter((f) => !currentFailures.includes(f));
162
+
163
+ return {
164
+ hasRegressions: regressions.length > 0,
165
+ regressions,
166
+ fixed,
167
+ baselineFailureCount: baselineFailures.length,
168
+ currentFailureCount: currentFailures.length,
169
+ };
170
+ },
171
+ });
172
+
173
+ // ============================================
174
+ // Helpers
175
+ // ============================================
176
+
177
+ async function runCommand(
178
+ command: string,
179
+ cwd: string,
180
+ timeoutMs: number
181
+ ): Promise<{
182
+ exitCode: number | null;
183
+ stdout: string;
184
+ stderr: string;
185
+ durationMs: number;
186
+ timedOut?: boolean;
187
+ }> {
188
+ const { spawn } = await import("child_process");
189
+
190
+ return new Promise((resolve) => {
191
+ const startTime = Date.now();
192
+ let stdout = "";
193
+ let stderr = "";
194
+ let timedOut = false;
195
+
196
+ const proc = spawn("bash", ["-c", command], {
197
+ cwd,
198
+ env: {
199
+ ...process.env,
200
+ HOME: "/home/user",
201
+ PATH: "/home/user/.bun/bin:/usr/local/bin:/usr/bin:/bin",
202
+ },
203
+ });
204
+
205
+ const timer = setTimeout(() => {
206
+ timedOut = true;
207
+ proc.kill("SIGTERM");
208
+ setTimeout(() => proc.kill("SIGKILL"), 1000);
209
+ }, timeoutMs);
210
+
211
+ proc.stdout.on("data", (data) => {
212
+ stdout += data.toString();
213
+ if (stdout.length > 50000) stdout = stdout.slice(-50000);
214
+ });
215
+
216
+ proc.stderr.on("data", (data) => {
217
+ stderr += data.toString();
218
+ if (stderr.length > 50000) stderr = stderr.slice(-50000);
219
+ });
220
+
221
+ proc.on("close", (code) => {
222
+ clearTimeout(timer);
223
+ resolve({
224
+ exitCode: code,
225
+ stdout,
226
+ stderr,
227
+ durationMs: Date.now() - startTime,
228
+ timedOut,
229
+ });
230
+ });
231
+
232
+ proc.on("error", (error) => {
233
+ clearTimeout(timer);
234
+ resolve({
235
+ exitCode: null,
236
+ stdout,
237
+ stderr: error.message,
238
+ durationMs: Date.now() - startTime,
239
+ });
240
+ });
241
+ });
242
+ }
243
+
244
+ function detectTestCommand(cwd: string): string {
245
+ // TODO: Actually check for package.json, etc.
246
+ // For now, default to bun test
247
+ return "bun test";
248
+ }
249
+
250
+ function parseTestFailures(output: string): string[] {
251
+ const failures: string[] = [];
252
+
253
+ // Parse common test output formats
254
+ // Vitest/Jest format: "FAIL path/to/test.ts"
255
+ const failRegex = /FAIL\s+(.+)/g;
256
+ let match;
257
+ while ((match = failRegex.exec(output)) !== null) {
258
+ failures.push(match[1].trim());
259
+ }
260
+
261
+ // Also look for "✗" or "✕" markers
262
+ const xRegex = /[✗✕]\s+(.+)/g;
263
+ while ((match = xRegex.exec(output)) !== null) {
264
+ failures.push(match[1].trim());
265
+ }
266
+
267
+ return [...new Set(failures)]; // Dedupe
268
+ }
@@ -0,0 +1,101 @@
1
+ /**
2
+ * Verification - Queries and Mutations
3
+ *
4
+ * Store and retrieve verification results.
5
+ * Actions that run actual verification are in verification.actions.ts
6
+ */
7
+
8
+ import { mutation, query } from "../_generated/server";
9
+ import { v } from "convex/values";
10
+
11
+ // ============================================
12
+ // Mutations (store verification results)
13
+ // ============================================
14
+
15
+ /**
16
+ * Store verification result for an edit
17
+ */
18
+ export const storeResult = mutation({
19
+ args: {
20
+ editId: v.optional(v.id("editHistory")),
21
+ path: v.string(),
22
+ success: v.boolean(),
23
+ checks: v.array(
24
+ v.object({
25
+ name: v.string(),
26
+ success: v.boolean(),
27
+ output: v.optional(v.string()),
28
+ durationMs: v.optional(v.number()),
29
+ })
30
+ ),
31
+ threadId: v.optional(v.string()),
32
+ },
33
+ handler: async (ctx, args) => {
34
+ return await ctx.db.insert("verificationResults", {
35
+ editId: args.editId,
36
+ path: args.path,
37
+ success: args.success,
38
+ checks: args.checks,
39
+ threadId: args.threadId,
40
+ createdAt: Date.now(),
41
+ });
42
+ },
43
+ });
44
+
45
+ /**
46
+ * Store test suite baseline
47
+ */
48
+ export const storeBaseline = mutation({
49
+ args: {
50
+ threadId: v.string(),
51
+ result: v.any(), // TestSuiteResult
52
+ },
53
+ handler: async (ctx, args) => {
54
+ // Remove old baselines for this thread
55
+ const existing = await ctx.db
56
+ .query("testBaselines")
57
+ .withIndex("by_thread", (q) => q.eq("threadId", args.threadId))
58
+ .collect();
59
+
60
+ for (const baseline of existing) {
61
+ await ctx.db.delete(baseline._id);
62
+ }
63
+
64
+ return await ctx.db.insert("testBaselines", {
65
+ threadId: args.threadId,
66
+ result: args.result,
67
+ createdAt: Date.now(),
68
+ });
69
+ },
70
+ });
71
+
72
+ // ============================================
73
+ // Queries
74
+ // ============================================
75
+
76
+ /**
77
+ * Get verification results for a file
78
+ */
79
+ export const getResultsForFile = query({
80
+ args: { path: v.string() },
81
+ handler: async (ctx, args) => {
82
+ return await ctx.db
83
+ .query("verificationResults")
84
+ .withIndex("by_path", (q) => q.eq("path", args.path))
85
+ .order("desc")
86
+ .take(10);
87
+ },
88
+ });
89
+
90
+ /**
91
+ * Get test baseline for thread
92
+ */
93
+ export const getBaseline = query({
94
+ args: { threadId: v.string() },
95
+ handler: async (ctx, args) => {
96
+ return await ctx.db
97
+ .query("testBaselines")
98
+ .withIndex("by_thread", (q) => q.eq("threadId", args.threadId))
99
+ .first();
100
+ },
101
+ });
@@ -0,0 +1,25 @@
1
+ {
2
+ /* This TypeScript project config describes the environment that
3
+ * Convex functions run in and is used to typecheck them.
4
+ * You can modify it, but some settings are required to use Convex.
5
+ */
6
+ "compilerOptions": {
7
+ /* These settings are not required by Convex and can be modified. */
8
+ "allowJs": true,
9
+ "strict": true,
10
+ "moduleResolution": "Bundler",
11
+ "jsx": "react-jsx",
12
+ "skipLibCheck": true,
13
+ "allowSyntheticDefaultImports": true,
14
+
15
+ /* These compiler options are required by Convex */
16
+ "target": "ESNext",
17
+ "lib": ["ES2021", "dom"],
18
+ "forceConsistentCasingInFileNames": true,
19
+ "module": "ESNext",
20
+ "isolatedModules": true,
21
+ "noEmit": true
22
+ },
23
+ "include": ["./**/*"],
24
+ "exclude": ["./_generated"]
25
+ }
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Code Execution Helpers
3
+ *
4
+ * Pure functions for parsing and preparing code for execution.
5
+ * These don't require Node.js APIs.
6
+ */
7
+
8
+ /**
9
+ * Extract code blocks from LLM response text.
10
+ *
11
+ * Supports:
12
+ * - ```typescript ... ```
13
+ * - ```ts ... ```
14
+ * - ```javascript ... ```
15
+ * - ```js ... ```
16
+ * - ``` ... ``` (unmarked, treated as TypeScript)
17
+ */
18
+ export function extractCodeBlocks(text: string): string[] {
19
+ const blocks: string[] = [];
20
+
21
+ // Match fenced code blocks
22
+ const fenceRegex = /```(?:typescript|ts|javascript|js)?\s*\n([\s\S]*?)```/g;
23
+ let match;
24
+
25
+ while ((match = fenceRegex.exec(text)) !== null) {
26
+ const code = match[1].trim();
27
+ if (code.length > 0) {
28
+ blocks.push(code);
29
+ }
30
+ }
31
+
32
+ return blocks;
33
+ }
34
+
35
+ /**
36
+ * Wrap code to ensure it can import from KSAs.
37
+ *
38
+ * Adds the necessary import path setup if not already present.
39
+ */
40
+ export function wrapCodeForExecution(code: string): string {
41
+ // If code already has imports from KSAs, use it as-is
42
+ if (code.includes("from './ksa/") || code.includes('from "./ksa/')) {
43
+ return code;
44
+ }
45
+
46
+ // If code has imports from 'ksa/', adjust the path
47
+ if (code.includes("from 'ksa/") || code.includes('from "ksa/')) {
48
+ return code.replace(/from ['"]KSAs\//g, "from './ksa/");
49
+ }
50
+
51
+ return code;
52
+ }
@@ -0,0 +1,19 @@
1
+ /**
2
+ * lakitu build
3
+ *
4
+ * Build E2B sandbox template with pre-deployed Convex functions.
5
+ *
6
+ * Strategy:
7
+ * 1. Start local convex-backend
8
+ * 2. Deploy sandbox functions with `convex dev --once`
9
+ * 3. Capture the state directory
10
+ * 4. Build E2B template with pre-built state baked in
11
+ */
12
+ interface BuildOptions {
13
+ base?: boolean;
14
+ custom?: boolean;
15
+ baseId?: string;
16
+ }
17
+ export declare function build(options: BuildOptions): Promise<void>;
18
+ export {};
19
+ //# sourceMappingURL=build.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../../cli/commands/build.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAWH,UAAU,YAAY;IACpB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAyND,wBAAsB,KAAK,CAAC,OAAO,EAAE,YAAY,iBAgBhD"}