@tarcisiopgs/lisa 1.37.1 → 1.38.1

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/README.md CHANGED
@@ -38,7 +38,7 @@ If something fails — pre-push hooks, quota limits, stuck processes — Lisa ha
38
38
  ## Features
39
39
 
40
40
  - **7 issue trackers** — Linear, GitHub Issues, GitLab Issues, Jira, Trello, Plane, Shortcut
41
- - **8 AI agents** — Claude Code, Gemini CLI, GitHub Copilot CLI, Cursor Agent, Aider, Goose, OpenCode, Codex
41
+ - **9 AI agents** — Claude Code, Gemini CLI, GitHub Copilot CLI, Cursor Agent, Aider, Goose, OpenCode, Codex, Kilo Code
42
42
  - **AI planning** — describe a goal, the AI brainstorms with you, decomposes it into issues with dependencies, created in your tracker
43
43
  - **Language-aware** — responds in the same language you write your goal in
44
44
  - **Spec compliance** — LLM-verified acceptance criteria check before PR creation, with auto-retry
@@ -67,6 +67,7 @@ If something fails — pre-push hooks, quota limits, stuck processes — Lisa ha
67
67
  | Gemini CLI | `gemini` | Goose | `goose` |
68
68
  | GitHub Copilot CLI | `copilot` | Aider | `aider` |
69
69
  | OpenCode | `opencode` | OpenAI Codex | `codex` |
70
+ | Kilo Code | `kilo` | | |
70
71
 
71
72
  Configure models and provider-specific options:
72
73
 
@@ -19,7 +19,7 @@ import {
19
19
  readContext,
20
20
  resolveModels,
21
21
  runWithFallback
22
- } from "./chunk-YRKJONH5.js";
22
+ } from "./chunk-MQG6ANVU.js";
23
23
  import {
24
24
  kanbanEmitter
25
25
  } from "./chunk-LR2GREZS.js";
@@ -90,7 +90,8 @@ var VALID_PROVIDERS = [
90
90
  "cursor",
91
91
  "goose",
92
92
  "aider",
93
- "codex"
93
+ "codex",
94
+ "kilo"
94
95
  ];
95
96
  var VALID_SOURCES = [
96
97
  "linear",
@@ -1562,7 +1563,9 @@ import { resolve as resolve6 } from "path";
1562
1563
  import { execa as execa5 } from "execa";
1563
1564
 
1564
1565
  // src/enrichment.ts
1565
- import { execSync } from "child_process";
1566
+ import { execFile } from "child_process";
1567
+ import { promisify } from "util";
1568
+ var execFileAsync = promisify(execFile);
1566
1569
  var STOP_WORDS = /* @__PURE__ */ new Set([
1567
1570
  "the",
1568
1571
  "a",
@@ -1786,24 +1789,43 @@ function extractKeywords(text) {
1786
1789
  const words = cleaned.split(/[\s/\\.,;:!?'"()[\]{}<>=+\-*&^%$@#~`|]+/).map((w) => w.toLowerCase().trim()).filter((w) => w.length >= 3 && !STOP_WORDS.has(w)).filter((w) => !/^\d+$/.test(w));
1787
1790
  return [...new Set(words)];
1788
1791
  }
1789
- function enrichContext(cwd, issue) {
1792
+ async function enrichContext(cwd, issue) {
1790
1793
  const keywords = extractKeywords(`${issue.title} ${issue.description}`);
1791
1794
  if (keywords.length === 0) return null;
1792
- const excludeDirs = EXCLUDE_DIRS.map((d) => `--exclude-dir=${d}`).join(" ");
1793
- const excludeExts = EXCLUDE_EXTENSIONS.map((e) => `--exclude=${e}`).join(" ");
1795
+ const excludeDirArgs = EXCLUDE_DIRS.flatMap((d) => ["--exclude-dir", d]);
1796
+ const excludeExtArgs = EXCLUDE_EXTENSIONS.flatMap((e) => ["--exclude", e]);
1797
+ const includeArgs = [
1798
+ "*.ts",
1799
+ "*.tsx",
1800
+ "*.js",
1801
+ "*.jsx",
1802
+ "*.py",
1803
+ "*.rb",
1804
+ "*.go",
1805
+ "*.rs",
1806
+ "*.java",
1807
+ "*.yaml",
1808
+ "*.yml",
1809
+ "*.json"
1810
+ ].flatMap((p) => ["--include", p]);
1794
1811
  const fileCounts = /* @__PURE__ */ new Map();
1795
- for (const keyword of keywords.slice(0, 15)) {
1812
+ const searches = keywords.slice(0, 15).map(async (keyword) => {
1796
1813
  try {
1797
- const result = execSync(
1798
- `grep -rl ${excludeDirs} ${excludeExts} -i --include='*.ts' --include='*.tsx' --include='*.js' --include='*.jsx' --include='*.py' --include='*.rb' --include='*.go' --include='*.rs' --include='*.java' --include='*.yaml' --include='*.yml' --include='*.json' -- ${JSON.stringify(keyword)} . 2>/dev/null || true`,
1814
+ const { stdout } = await execFileAsync(
1815
+ "grep",
1816
+ ["-rl", ...excludeDirArgs, ...excludeExtArgs, "-i", ...includeArgs, "--", keyword, "."],
1799
1817
  { cwd, encoding: "utf-8", timeout: 5e3, maxBuffer: 1024 * 1024 }
1800
1818
  );
1801
- const files = result.trim().split("\n").filter(Boolean);
1802
- for (const file of files) {
1803
- const rel = file.startsWith("./") ? file.slice(2) : file;
1804
- fileCounts.set(rel, (fileCounts.get(rel) ?? 0) + 1);
1805
- }
1819
+ return stdout.trim().split("\n").filter(Boolean);
1806
1820
  } catch {
1821
+ return [];
1822
+ }
1823
+ });
1824
+ const results = await Promise.all(searches);
1825
+ for (const files of results) {
1826
+ for (const file of files) {
1827
+ const rel = file.startsWith("./") ? file.slice(2) : file;
1828
+ fileCounts.set(rel, (fileCounts.get(rel) ?? 0) + 1);
1807
1829
  }
1808
1830
  }
1809
1831
  if (fileCounts.size === 0) return null;
@@ -1868,9 +1890,15 @@ async function createWorktree(repoRoot, branchName, baseBranch) {
1868
1890
  rmSync(worktreePath, { recursive: true, force: true });
1869
1891
  }
1870
1892
  }
1871
- await execa2("git", ["fetch", "origin", baseBranch], { cwd: repoRoot });
1893
+ await execa2("git", ["fetch", "origin", baseBranch], {
1894
+ cwd: repoRoot,
1895
+ stdin: "ignore",
1896
+ timeout: 3e4
1897
+ });
1872
1898
  await execa2("git", ["worktree", "add", "-b", branchName, worktreePath, `origin/${baseBranch}`], {
1873
- cwd: repoRoot
1899
+ cwd: repoRoot,
1900
+ stdin: "ignore",
1901
+ timeout: 3e4
1874
1902
  });
1875
1903
  return worktreePath;
1876
1904
  }
@@ -3046,7 +3074,7 @@ async function runNativeWorktreeSession(config, issue, logFile, session, models,
3046
3074
  const pm = detectPackageManager(repoPath);
3047
3075
  const projectContext = analyzeProject(repoPath);
3048
3076
  const repoContextMd = readContext(repoPath);
3049
- const relevantFiles = enrichContext(repoPath, issue);
3077
+ const relevantFiles = await enrichContext(repoPath, issue);
3050
3078
  const workspace = resolve6(config.workspace);
3051
3079
  const hookEnv = buildHookEnv(issue.id, issue.title, "", repoPath);
3052
3080
  const lifecycleEnv = await startInfra(issue.id, repoPath, config);
@@ -3196,7 +3224,7 @@ async function runManualWorktreeSession(config, issue, logFile, session, models,
3196
3224
  const pm = detectPackageManager(worktreePath);
3197
3225
  const projectContext = analyzeProject(worktreePath);
3198
3226
  const repoContextMd = readContext(repoPath);
3199
- const relevantFiles = enrichContext(worktreePath, issue);
3227
+ const relevantFiles = await enrichContext(worktreePath, issue);
3200
3228
  const lifecycleEnv = await startInfra(issue.id, worktreePath, config);
3201
3229
  const manifestPath = getManifestPath(worktreePath, issue.id);
3202
3230
  if (!await executeHook("before_run", config.hooks, worktreePath, hookEnv)) {
@@ -3817,7 +3845,7 @@ async function runBranchSession(config, issue, logFile, session, models, source,
3817
3845
  const pm = detectPackageManager(workspace);
3818
3846
  const projectContext = analyzeProject(workspace);
3819
3847
  const repoContextMd = readContext(workspace);
3820
- const relevantFiles = enrichContext(workspace, issue);
3848
+ const relevantFiles = await enrichContext(workspace, issue);
3821
3849
  const lifecycleEnv = await startInfra(issue.id, workspace, config);
3822
3850
  if (!await executeHook("before_run", config.hooks, workspace, hookEnv)) {
3823
3851
  return hookFailure(defaultProvider(models), "before_run hook failed");
@@ -2080,6 +2080,30 @@ var GooseProvider = class {
2080
2080
  }
2081
2081
  };
2082
2082
 
2083
+ // src/providers/kilo.ts
2084
+ var KILO_ERROR_PATTERN = /^Error /;
2085
+ var KiloProvider = class {
2086
+ name = "kilo";
2087
+ async isAvailable() {
2088
+ return isCommandAvailable("kilo");
2089
+ }
2090
+ async run(prompt, opts) {
2091
+ try {
2092
+ const config = {
2093
+ name: "kilo",
2094
+ buildCommand: (promptCatExpr) => `kilo run --auto ${promptCatExpr}`,
2095
+ logLine: "kilo run --auto",
2096
+ kanbanLine: `$ kilo run --auto <prompt: ${prompt.length} chars>
2097
+ `,
2098
+ errorPattern: KILO_ERROR_PATTERN
2099
+ };
2100
+ return await runProviderProcess(config, prompt, opts);
2101
+ } catch (err) {
2102
+ return { success: false, output: formatError(err), duration: 0 };
2103
+ }
2104
+ }
2105
+ };
2106
+
2083
2107
  // src/providers/opencode.ts
2084
2108
  var OpenCodeProvider = class {
2085
2109
  name = "opencode";
@@ -2114,7 +2138,8 @@ var providers = {
2114
2138
  cursor: () => new CursorProvider(),
2115
2139
  goose: () => new GooseProvider(),
2116
2140
  aider: () => new AiderProvider(),
2117
- codex: () => new CodexProvider()
2141
+ codex: () => new CodexProvider(),
2142
+ kilo: () => new KiloProvider()
2118
2143
  };
2119
2144
  async function getAllProvidersWithAvailability() {
2120
2145
  const all = Object.values(providers).map((f) => f());
@@ -4119,7 +4144,8 @@ function resolveModels(config) {
4119
4144
  "cursor",
4120
4145
  "goose",
4121
4146
  "aider",
4122
- "codex"
4147
+ "codex",
4148
+ "kilo"
4123
4149
  ]);
4124
4150
  for (const m of providerModels) {
4125
4151
  if (knownProviders.has(m) && m !== config.provider) {
@@ -5,7 +5,7 @@ import {
5
5
  resolveModels,
6
6
  runWithFallback,
7
7
  saveLineage
8
- } from "./chunk-YRKJONH5.js";
8
+ } from "./chunk-MQG6ANVU.js";
9
9
  import {
10
10
  normalizeLabels
11
11
  } from "./chunk-LR2GREZS.js";
package/dist/index.js CHANGED
@@ -14,7 +14,7 @@ import {
14
14
  runLoop,
15
15
  saveConfig,
16
16
  validateConfig
17
- } from "./chunk-ZERJ7TNX.js";
17
+ } from "./chunk-MC2IRJOL.js";
18
18
  import {
19
19
  CliError,
20
20
  buildExecutionWaves,
@@ -24,7 +24,7 @@ import {
24
24
  parseStructuredOutput,
25
25
  runPlanWizard,
26
26
  savePlan
27
- } from "./chunk-I5HJELVZ.js";
27
+ } from "./chunk-YC736WGU.js";
28
28
  import {
29
29
  buildContextMdBlock,
30
30
  createProvider,
@@ -34,7 +34,7 @@ import {
34
34
  readContext,
35
35
  resolveModels,
36
36
  runWithFallback
37
- } from "./chunk-YRKJONH5.js";
37
+ } from "./chunk-MQG6ANVU.js";
38
38
  import {
39
39
  kanbanEmitter
40
40
  } from "./chunk-LR2GREZS.js";
@@ -250,7 +250,8 @@ async function runConfigWizard(existing) {
250
250
  cursor: "Cursor Agent",
251
251
  goose: "Goose",
252
252
  aider: "Aider",
253
- codex: "OpenAI Codex"
253
+ codex: "OpenAI Codex",
254
+ kilo: "Kilo Code"
254
255
  };
255
256
  const providerModels = {
256
257
  claude: ["claude-opus-4-6", "claude-sonnet-4-6", "claude-haiku-4-5", "claude-sonnet-4-5"],
@@ -275,6 +276,7 @@ async function runConfigWizard(existing) {
275
276
  "gpt-5.4"
276
277
  ]
277
278
  // cursor: populated dynamically below (fetchCursorModels)
279
+ // kilo: model configured in Kilo's own config (~/.config/kilo/kilo.jsonc)
278
280
  };
279
281
  const allProviders = await getAllProvidersWithAvailability();
280
282
  const available = allProviders.filter((r) => r.available).map((r) => r.provider);
@@ -289,7 +291,8 @@ async function runConfigWizard(existing) {
289
291
  ${pc.bold("GitHub Copilot CLI")} ${pc.dim("npm i -g @github/copilot-cli")}
290
292
  ${pc.bold("OpenAI Codex")} ${pc.dim("npm i -g @openai/codex")}
291
293
  ${pc.bold("Goose")} ${pc.dim("https://block.github.io/goose")}
292
- ${pc.bold("Aider")} ${pc.dim("pip install aider-chat")}`
294
+ ${pc.bold("Aider")} ${pc.dim("pip install aider-chat")}
295
+ ${pc.bold("Kilo Code")} ${pc.dim("npm i -g @kilocode/cli")}`
293
296
  );
294
297
  return process.exit(1);
295
298
  }
@@ -1847,7 +1850,7 @@ async function reviewAndCreate(plan2, planPath, opts) {
1847
1850
  log("Run `lisa run` when ready.");
1848
1851
  return;
1849
1852
  }
1850
- const { runLoop: runLoop2 } = await import("./loop-FKUQEJVU.js");
1853
+ const { runLoop: runLoop2 } = await import("./loop-6G27WHYO.js");
1851
1854
  const waves = buildExecutionWaves(plan2.issues);
1852
1855
  const maxWaveSize = Math.max(...waves.map((w) => w.length));
1853
1856
  await runLoop2(config2, {
@@ -2317,7 +2320,7 @@ Add them to your ${shell} and run: source ${shell}`));
2317
2320
  const initialCards = persistence.load();
2318
2321
  persistedCards = initialCards;
2319
2322
  persistence.start();
2320
- const { registerPlanBridge } = await import("./tui-bridge-MMP6OGHK.js");
2323
+ const { registerPlanBridge } = await import("./tui-bridge-L5NWRFEF.js");
2321
2324
  const cleanupPlan = registerPlanBridge(merged);
2322
2325
  onBeforeExit = () => {
2323
2326
  persistence.stop();
@@ -4,10 +4,10 @@ import {
4
4
  cleanupEventListeners,
5
5
  runDemoLoop,
6
6
  runLoop
7
- } from "./chunk-ZERJ7TNX.js";
7
+ } from "./chunk-MC2IRJOL.js";
8
8
  import {
9
9
  WATCH_POLL_INTERVAL_MS
10
- } from "./chunk-YRKJONH5.js";
10
+ } from "./chunk-MQG6ANVU.js";
11
11
  import "./chunk-LR2GREZS.js";
12
12
  import "./chunk-ZOVVFU7B.js";
13
13
  import "./chunk-3EOEDL3T.js";
@@ -6,12 +6,12 @@ import {
6
6
  markdownToIssue,
7
7
  parseStructuredOutput,
8
8
  savePlan
9
- } from "./chunk-I5HJELVZ.js";
9
+ } from "./chunk-YC736WGU.js";
10
10
  import {
11
11
  createSource,
12
12
  resolveModels,
13
13
  runWithFallback
14
- } from "./chunk-YRKJONH5.js";
14
+ } from "./chunk-MQG6ANVU.js";
15
15
  import {
16
16
  kanbanEmitter
17
17
  } from "./chunk-LR2GREZS.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tarcisiopgs/lisa",
3
- "version": "1.37.1",
3
+ "version": "1.38.1",
4
4
  "description": "Autonomous issue resolver",
5
5
  "keywords": [
6
6
  "loop",