@tarcisiopgs/lisa 1.40.2 → 1.42.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/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
- - **9 AI agents** — Claude Code, Gemini CLI, GitHub Copilot CLI, Cursor Agent, Aider, Goose, OpenCode, Codex, Kilo Code
41
+ - **10 AI agents** — Claude Code, Gemini CLI, GitHub Copilot CLI, Cursor Agent, Aider, Goose, OpenCode, Codex, Kilo Code, MiMo 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,7 +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
+ | Kilo Code | `kilo` | MiMo Code | `mimo` |
71
71
 
72
72
  Configure models and provider-specific options:
73
73
 
@@ -5,10 +5,10 @@ import {
5
5
  resolveModels,
6
6
  runWithFallback,
7
7
  saveLineage
8
- } from "./chunk-YTUZFCU2.js";
8
+ } from "./chunk-YSFHP3A3.js";
9
9
  import {
10
10
  normalizeLabels
11
- } from "./chunk-SOV2YONG.js";
11
+ } from "./chunk-ZHB4S7SP.js";
12
12
  import {
13
13
  error,
14
14
  log,
@@ -111,6 +111,16 @@ function fetchOpenCodeModels() {
111
111
  return [];
112
112
  }
113
113
  }
114
+ function fetchMimoModels() {
115
+ try {
116
+ const raw = execSync("mimo models", { encoding: "utf-8", timeout: 1e4 });
117
+ const clean = raw.replace(/\x1b\[[0-9;]*[mGKHFA-Z]/g, "");
118
+ return clean.split("\n").map((l) => l.trim()).filter((m) => /^[a-z0-9][\w.-]*\/.+/i.test(m));
119
+ } catch (err) {
120
+ verbose(`Failed to fetch MiMo models: ${formatError(err)}`);
121
+ return [];
122
+ }
123
+ }
114
124
  function detectPlatformFromRemoteUrl(remoteUrl) {
115
125
  if (/github\.com/.test(remoteUrl)) return "cli";
116
126
  if (/gitlab\./.test(remoteUrl)) return "gitlab";
@@ -267,6 +277,7 @@ export {
267
277
  fetchCursorModels,
268
278
  fetchCopilotModels,
269
279
  fetchOpenCodeModels,
280
+ fetchMimoModels,
270
281
  detectPlatformFromRemoteUrl,
271
282
  detectPlatform,
272
283
  verifyPlatformCredential,
@@ -19,10 +19,10 @@ import {
19
19
  readContext,
20
20
  resolveModels,
21
21
  runWithFallback
22
- } from "./chunk-YTUZFCU2.js";
22
+ } from "./chunk-YSFHP3A3.js";
23
23
  import {
24
24
  kanbanEmitter
25
- } from "./chunk-SOV2YONG.js";
25
+ } from "./chunk-ZHB4S7SP.js";
26
26
  import {
27
27
  appendPlatformAttribution,
28
28
  appendPlatformProofOfWork,
@@ -91,7 +91,8 @@ var VALID_PROVIDERS = [
91
91
  "goose",
92
92
  "aider",
93
93
  "codex",
94
- "kilo"
94
+ "kilo",
95
+ "mimo"
95
96
  ];
96
97
  var VALID_SOURCES = [
97
98
  "linear",
@@ -1240,46 +1241,52 @@ async function pullBaseBranch(config) {
1240
1241
  }
1241
1242
  var AUTO_MERGE_CI_TIMEOUT_MS = 10 * 60 * 1e3;
1242
1243
  var AUTO_MERGE_POLL_MS = 15e3;
1243
- async function autoMergePr(prUrl, issueId, config) {
1244
- if (!config.pr?.auto_merge) return;
1244
+ async function autoMergeAllPrs(prUrls, issueId, config) {
1245
+ if (!config.pr?.auto_merge || prUrls.length === 0) return;
1245
1246
  const { checkPrCiStatus, mergePr } = await import("./merge-NWSEV3FR.js");
1246
- log(`Waiting for CI before auto-merge of ${issueId}...`);
1247
+ kanbanEmitter.emit("issue:auto-merge-status", issueId, "waiting");
1247
1248
  kanbanEmitter.emit("issue:ci-status", issueId, "pending");
1248
- const deadline = Date.now() + AUTO_MERGE_CI_TIMEOUT_MS;
1249
- while (Date.now() < deadline) {
1250
- if (isShuttingDown() || hasUserQuitFromWatchPrompt()) return;
1251
- const ciStatus = await checkPrCiStatus(prUrl);
1252
- if (ciStatus === "passing") {
1253
- kanbanEmitter.emit("issue:ci-status", issueId, "passing");
1254
- log(`CI passed for ${issueId}. Auto-merging...`);
1255
- const result = await mergePr(prUrl);
1256
- if (result.success) {
1257
- ok(`Auto-merged: ${prUrl}`);
1258
- kanbanEmitter.emit("issue:merged", issueId);
1259
- } else {
1260
- warn(`Auto-merge failed for ${issueId}: ${result.error}`);
1249
+ log(
1250
+ `Waiting for CI before auto-merge of ${issueId} (${prUrls.length} PR${prUrls.length > 1 ? "s" : ""})...`
1251
+ );
1252
+ const mergeOnePr = async (prUrl) => {
1253
+ const deadline = Date.now() + AUTO_MERGE_CI_TIMEOUT_MS;
1254
+ while (Date.now() < deadline) {
1255
+ if (isShuttingDown() || hasUserQuitFromWatchPrompt()) {
1256
+ return { url: prUrl, success: false, error: "shutdown" };
1261
1257
  }
1262
- return;
1263
- }
1264
- if (ciStatus === "failing") {
1265
- kanbanEmitter.emit("issue:ci-status", issueId, "failing");
1266
- warn(`CI failed for ${issueId}. Skipping auto-merge.`);
1267
- return;
1268
- }
1269
- if (ciStatus === "unknown") {
1270
- log(`No CI checks found for ${issueId}. Auto-merging...`);
1271
- const result = await mergePr(prUrl);
1272
- if (result.success) {
1273
- ok(`Auto-merged: ${prUrl}`);
1274
- kanbanEmitter.emit("issue:merged", issueId);
1275
- } else {
1276
- warn(`Auto-merge failed for ${issueId}: ${result.error}`);
1258
+ const ciStatus = await checkPrCiStatus(prUrl);
1259
+ if (ciStatus === "passing" || ciStatus === "unknown") {
1260
+ const result = await mergePr(prUrl);
1261
+ if (result.success) {
1262
+ ok(`Merged: ${prUrl}`);
1263
+ return { url: prUrl, success: true };
1264
+ }
1265
+ return { url: prUrl, success: false, error: result.error };
1277
1266
  }
1278
- return;
1267
+ if (ciStatus === "failing") {
1268
+ return { url: prUrl, success: false, error: "CI failed" };
1269
+ }
1270
+ await sleep(AUTO_MERGE_POLL_MS);
1271
+ }
1272
+ return { url: prUrl, success: false, error: "CI timeout" };
1273
+ };
1274
+ kanbanEmitter.emit("issue:auto-merge-status", issueId, "merging");
1275
+ const results = await Promise.all(prUrls.map(mergeOnePr));
1276
+ const allMerged = results.every((r) => r.success);
1277
+ const failed = results.filter((r) => !r.success);
1278
+ if (allMerged) {
1279
+ kanbanEmitter.emit("issue:ci-status", issueId, "passing");
1280
+ kanbanEmitter.emit("issue:auto-merge-status", issueId, "merged");
1281
+ kanbanEmitter.emit("issue:merged", issueId);
1282
+ ok(`All ${prUrls.length} PRs auto-merged for ${issueId}`);
1283
+ } else {
1284
+ kanbanEmitter.emit("issue:ci-status", issueId, "failing");
1285
+ kanbanEmitter.emit("issue:auto-merge-status", issueId, "failed");
1286
+ for (const f of failed) {
1287
+ warn(`Auto-merge failed for ${f.url}: ${f.error}`);
1279
1288
  }
1280
- await sleep(AUTO_MERGE_POLL_MS);
1281
1289
  }
1282
- warn(`CI did not complete within timeout for ${issueId}. Skipping auto-merge.`);
1283
1290
  }
1284
1291
  function appendSessionLog(logFile, result) {
1285
1292
  try {
@@ -2774,6 +2781,33 @@ function extractPrUrlFromOutput(output) {
2774
2781
  }
2775
2782
  return null;
2776
2783
  }
2784
+ function extractAllPrUrlsFromOutput(output) {
2785
+ const patterns = [
2786
+ /https?:\/\/github\.com\/[^/]+\/[^/]+\/pull\/\d+/g,
2787
+ /https?:\/\/[^/]*gitlab[^/]*\/[^/].+?\/-\/merge_requests\/\d+/g,
2788
+ /https?:\/\/bitbucket\.org\/[^/]+\/[^/]+\/pull-requests\/\d+/g
2789
+ ];
2790
+ const urls = /* @__PURE__ */ new Set();
2791
+ for (const pattern of patterns) {
2792
+ for (const match of output.matchAll(pattern)) {
2793
+ urls.add(match[0]);
2794
+ }
2795
+ }
2796
+ return [...urls];
2797
+ }
2798
+ function readAllManifestPrUrls(filePath) {
2799
+ if (!existsSync6(filePath)) return [];
2800
+ try {
2801
+ const parsed = JSON.parse(readFileSync6(filePath, "utf-8").trim());
2802
+ if (Array.isArray(parsed)) {
2803
+ return parsed.map((m) => m.prUrl).filter((url) => !!url);
2804
+ }
2805
+ const single = parsed;
2806
+ return single.prUrl ? [single.prUrl] : [];
2807
+ } catch {
2808
+ return [];
2809
+ }
2810
+ }
2777
2811
  function readPlanFile(filePath) {
2778
2812
  if (!existsSync6(filePath)) return null;
2779
2813
  try {
@@ -3286,7 +3320,7 @@ async function runNativeWorktreeSession(config, issue, logFile, session, models,
3286
3320
  }
3287
3321
  }
3288
3322
  if (worktreePath) await cleanupWorktree(repoPath, worktreePath);
3289
- await autoMergePr(prUrl, issue.id, config);
3323
+ await autoMergeAllPrs([prUrl], issue.id, config);
3290
3324
  await reporter.finish([prUrl]);
3291
3325
  ok(`Session ${session} complete for ${issue.id}`);
3292
3326
  return {
@@ -3564,7 +3598,7 @@ async function runManualWorktreeSession(config, issue, logFile, session, models,
3564
3598
  }
3565
3599
  await executeHook("before_remove", config.hooks, worktreePath, hookEnv);
3566
3600
  await cleanupWorktree(repoPath, worktreePath);
3567
- await autoMergePr(prUrl, issue.id, config);
3601
+ await autoMergeAllPrs([prUrl], issue.id, config);
3568
3602
  await reporter.finish([prUrl]);
3569
3603
  updateSessionState(workspace, issue.id, "done");
3570
3604
  removeSessionRecord(workspace, issue.id);
@@ -3999,11 +4033,12 @@ async function runBranchSession(config, issue, logFile, session, models, source,
3999
4033
  return failureResult(result.providerUsed, result);
4000
4034
  }
4001
4035
  const manifest = readManifestFile(manifestPath);
4036
+ const allManifestPrUrls = readAllManifestPrUrls(manifestPath);
4002
4037
  try {
4003
4038
  unlinkSync4(manifestPath);
4004
4039
  } catch {
4005
4040
  }
4006
- let prUrl = manifest?.prUrl;
4041
+ let prUrl = manifest?.prUrl ?? allManifestPrUrls[0];
4007
4042
  if (!prUrl) {
4008
4043
  const extractedUrl = extractPrUrlFromOutput(result.output);
4009
4044
  if (extractedUrl) {
@@ -4011,6 +4046,12 @@ async function runBranchSession(config, issue, logFile, session, models, source,
4011
4046
  prUrl = extractedUrl;
4012
4047
  }
4013
4048
  }
4049
+ const allPrUrls = new Set(allManifestPrUrls);
4050
+ for (const url of extractAllPrUrlsFromOutput(result.output)) {
4051
+ allPrUrls.add(url);
4052
+ }
4053
+ if (prUrl) allPrUrls.add(prUrl);
4054
+ const prUrls = [...allPrUrls];
4014
4055
  if (!prUrl) {
4015
4056
  const hasChanges = await hasCodeChanges(workspace, config.base_branch);
4016
4057
  if (!hasChanges) {
@@ -4098,13 +4139,13 @@ async function runBranchSession(config, issue, logFile, session, models, source,
4098
4139
  }
4099
4140
  }
4100
4141
  }
4101
- await autoMergePr(prUrl, issue.id, config);
4102
- await reporter.finish([prUrl]);
4142
+ await autoMergeAllPrs(prUrls, issue.id, config);
4143
+ await reporter.finish(prUrls);
4103
4144
  ok(`Session ${session} complete for ${issue.id}`);
4104
4145
  return {
4105
4146
  success: true,
4106
4147
  providerUsed: result.providerUsed,
4107
- prUrls: [prUrl],
4148
+ prUrls,
4108
4149
  fallback: result
4109
4150
  };
4110
4151
  }
@@ -6,7 +6,7 @@ import {
6
6
  createApiClient,
7
7
  kanbanEmitter,
8
8
  normalizeLabels
9
- } from "./chunk-SOV2YONG.js";
9
+ } from "./chunk-ZHB4S7SP.js";
10
10
  import {
11
11
  buildPrCreateInstruction
12
12
  } from "./chunk-ZOVVFU7B.js";
@@ -2105,6 +2105,32 @@ var KiloProvider = class {
2105
2105
  }
2106
2106
  };
2107
2107
 
2108
+ // src/providers/mimo.ts
2109
+ var MIMO_ERROR_PATTERN = /^Error /;
2110
+ var MimoProvider = class {
2111
+ name = "mimo";
2112
+ async isAvailable() {
2113
+ return isCommandAvailable("mimo");
2114
+ }
2115
+ async run(prompt, opts) {
2116
+ try {
2117
+ if (opts.model) validateShellArg(opts.model, "model");
2118
+ const modelFlag = opts.model ? `--model ${opts.model}` : "";
2119
+ const config = {
2120
+ name: "mimo",
2121
+ buildCommand: (promptCatExpr) => `mimo run --dangerously-skip-permissions ${modelFlag} ${promptCatExpr}`,
2122
+ logLine: `mimo run --dangerously-skip-permissions ${modelFlag || "(default model)"}`,
2123
+ kanbanLine: `$ mimo run --dangerously-skip-permissions ${modelFlag || "(default model)"} <prompt: ${prompt.length} chars>
2124
+ `,
2125
+ errorPattern: MIMO_ERROR_PATTERN
2126
+ };
2127
+ return await runProviderProcess(config, prompt, opts);
2128
+ } catch (err) {
2129
+ return { success: false, output: formatError(err), duration: 0 };
2130
+ }
2131
+ }
2132
+ };
2133
+
2108
2134
  // src/providers/opencode.ts
2109
2135
  var OpenCodeProvider = class {
2110
2136
  name = "opencode";
@@ -2140,7 +2166,8 @@ var providers = {
2140
2166
  goose: () => new GooseProvider(),
2141
2167
  aider: () => new AiderProvider(),
2142
2168
  codex: () => new CodexProvider(),
2143
- kilo: () => new KiloProvider()
2169
+ kilo: () => new KiloProvider(),
2170
+ mimo: () => new MimoProvider()
2144
2171
  };
2145
2172
  async function getAllProvidersWithAvailability() {
2146
2173
  const all = Object.values(providers).map((f) => f());
@@ -4146,7 +4173,8 @@ function resolveModels(config) {
4146
4173
  "goose",
4147
4174
  "aider",
4148
4175
  "codex",
4149
- "kilo"
4176
+ "kilo",
4177
+ "mimo"
4150
4178
  ]);
4151
4179
  for (const m of providerModels) {
4152
4180
  if (knownProviders.has(m) && m !== config.provider) {
@@ -894,6 +894,11 @@ function useKanbanState(bellEnabled, initialCards = []) {
894
894
  const onCiStatus = (issueId, ciStatus) => {
895
895
  setCards((prev) => prev.map((c) => c.id === issueId ? { ...c, ciStatus } : c));
896
896
  };
897
+ const onAutoMergeStatus = (issueId, status) => {
898
+ setCards(
899
+ (prev) => prev.map((c) => c.id === issueId ? { ...c, autoMergeStatus: status } : c)
900
+ );
901
+ };
897
902
  const onReviewersUpdated = (issueId, reviewers) => {
898
903
  setCards((prev) => prev.map((c) => c.id === issueId ? { ...c, reviewers } : c));
899
904
  };
@@ -951,6 +956,7 @@ function useKanbanState(bellEnabled, initialCards = []) {
951
956
  kanbanEmitter.on("issue:log-file", onLogFile);
952
957
  kanbanEmitter.on("issue:substatus", onSubstatus);
953
958
  kanbanEmitter.on("issue:ci-status", onCiStatus);
959
+ kanbanEmitter.on("issue:auto-merge-status", onAutoMergeStatus);
954
960
  kanbanEmitter.on("issue:reviewers-updated", onReviewersUpdated);
955
961
  kanbanEmitter.on("issue:available-reviewers", onAvailableReviewers);
956
962
  kanbanEmitter.on("issue:output", onOutput);
@@ -1000,6 +1006,7 @@ function useKanbanState(bellEnabled, initialCards = []) {
1000
1006
  kanbanEmitter.off("issue:log-file", onLogFile);
1001
1007
  kanbanEmitter.off("issue:substatus", onSubstatus);
1002
1008
  kanbanEmitter.off("issue:ci-status", onCiStatus);
1009
+ kanbanEmitter.off("issue:auto-merge-status", onAutoMergeStatus);
1003
1010
  kanbanEmitter.off("issue:reviewers-updated", onReviewersUpdated);
1004
1011
  kanbanEmitter.off("issue:available-reviewers", onAvailableReviewers);
1005
1012
  kanbanEmitter.off("issue:output", onOutput);
@@ -6,13 +6,14 @@ import {
6
6
  detectPlatformFromRemoteUrl,
7
7
  fetchCopilotModels,
8
8
  fetchCursorModels,
9
+ fetchMimoModels,
9
10
  fetchOpenCodeModels,
10
11
  getGitRepoName,
11
12
  getMissingEnvVars,
12
13
  getVersion,
13
14
  isCursorFreePlan,
14
15
  verifyPlatformCredential
15
- } from "./chunk-MC4SAOF2.js";
16
+ } from "./chunk-JALGARX3.js";
16
17
  import "./chunk-YBM6JNRO.js";
17
18
  import "./chunk-HPWL5JRW.js";
18
19
  import "./chunk-4MZ2565Y.js";
@@ -23,6 +24,7 @@ export {
23
24
  detectPlatformFromRemoteUrl,
24
25
  fetchCopilotModels,
25
26
  fetchCursorModels,
27
+ fetchMimoModels,
26
28
  fetchOpenCodeModels,
27
29
  getGitRepoName,
28
30
  getMissingEnvVars,
package/dist/index.js CHANGED
@@ -14,7 +14,7 @@ import {
14
14
  runLoop,
15
15
  saveConfig,
16
16
  validateConfig
17
- } from "./chunk-BI6MR2UP.js";
17
+ } from "./chunk-VVYGYOPG.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-RZ53EOAY.js";
27
+ } from "./chunk-6ZWVYPR5.js";
28
28
  import {
29
29
  buildContextMdBlock,
30
30
  createProvider,
@@ -34,10 +34,10 @@ import {
34
34
  readContext,
35
35
  resolveModels,
36
36
  runWithFallback
37
- } from "./chunk-YTUZFCU2.js";
37
+ } from "./chunk-YSFHP3A3.js";
38
38
  import {
39
39
  kanbanEmitter
40
- } from "./chunk-SOV2YONG.js";
40
+ } from "./chunk-ZHB4S7SP.js";
41
41
  import {
42
42
  isProofOfWorkEnabled,
43
43
  isSpecComplianceEnabled,
@@ -55,11 +55,12 @@ import {
55
55
  detectPlatform,
56
56
  fetchCopilotModels,
57
57
  fetchCursorModels,
58
+ fetchMimoModels,
58
59
  fetchOpenCodeModels,
59
60
  getMissingEnvVars,
60
61
  getVersion,
61
62
  isCursorFreePlan
62
- } from "./chunk-MC4SAOF2.js";
63
+ } from "./chunk-JALGARX3.js";
63
64
  import {
64
65
  isGhCliAvailable
65
66
  } from "./chunk-YBM6JNRO.js";
@@ -251,7 +252,8 @@ async function runConfigWizard(existing) {
251
252
  goose: "Goose",
252
253
  aider: "Aider",
253
254
  codex: "OpenAI Codex",
254
- kilo: "Kilo Code"
255
+ kilo: "Kilo Code",
256
+ mimo: "MiMo Code"
255
257
  };
256
258
  const providerModels = {
257
259
  claude: ["claude-opus-4-6", "claude-sonnet-4-6", "claude-haiku-4-5", "claude-sonnet-4-5"],
@@ -292,7 +294,8 @@ async function runConfigWizard(existing) {
292
294
  ${pc.bold("OpenAI Codex")} ${pc.dim("npm i -g @openai/codex")}
293
295
  ${pc.bold("Goose")} ${pc.dim("https://block.github.io/goose")}
294
296
  ${pc.bold("Aider")} ${pc.dim("pip install aider-chat")}
295
- ${pc.bold("Kilo Code")} ${pc.dim("npm i -g @kilocode/cli")}`
297
+ ${pc.bold("Kilo Code")} ${pc.dim("npm i -g @kilocode/cli")}
298
+ ${pc.bold("MiMo Code")} ${pc.dim("npm i -g @mimo-ai/cli")}`
296
299
  );
297
300
  return process.exit(1);
298
301
  }
@@ -426,6 +429,9 @@ remove them or set the file to ${pc.cyan("{}")} \u2014 MCP tools can cause OpenC
426
429
  "google/gemini-2.5-pro",
427
430
  "google/gemini-2.5-flash"
428
431
  ];
432
+ } else if (providerName === "mimo") {
433
+ const dynamic = fetchMimoModels();
434
+ availableModels = dynamic.length > 0 ? dynamic : ["mimo/mimo-auto", "xiaomi/mimo-v2.5-pro", "xiaomi/mimo-v2.5", "xiaomi/mimo-v2-flash"];
429
435
  }
430
436
  if (availableModels && availableModels.length > 0) {
431
437
  const modelSelection = await clack.multiselect({
@@ -1861,7 +1867,7 @@ async function reviewAndCreate(plan2, planPath, opts) {
1861
1867
  log("Run `lisa run` when ready.");
1862
1868
  return;
1863
1869
  }
1864
- const { runLoop: runLoop2 } = await import("./loop-RWZJG7BG.js");
1870
+ const { runLoop: runLoop2 } = await import("./loop-3OBNPSYF.js");
1865
1871
  const waves = buildExecutionWaves(plan2.issues);
1866
1872
  const maxWaveSize = Math.max(...waves.map((w) => w.length));
1867
1873
  await runLoop2(config2, {
@@ -1957,6 +1963,7 @@ function resolveCard(card) {
1957
1963
  prUrls: card.prUrls,
1958
1964
  merged: card.merged,
1959
1965
  ciStatus: card.ciStatus,
1966
+ autoMergeStatus: card.autoMergeStatus,
1960
1967
  logFile: card.logFile,
1961
1968
  outputLog: card.outputLogTail.join("\n")
1962
1969
  };
@@ -1984,6 +1991,7 @@ function resolveCard(card) {
1984
1991
  killed: card.killed,
1985
1992
  merged: card.merged,
1986
1993
  ciStatus: card.ciStatus,
1994
+ autoMergeStatus: card.autoMergeStatus,
1987
1995
  logFile: card.logFile,
1988
1996
  outputLog: card.outputLogTail.join("\n")
1989
1997
  };
@@ -2072,6 +2080,12 @@ var KanbanPersistence = class {
2072
2080
  this.updateCard(issueId, { ciStatus });
2073
2081
  this.scheduleFlush();
2074
2082
  });
2083
+ on("issue:auto-merge-status", (issueId, autoMergeStatus) => {
2084
+ this.updateCard(issueId, {
2085
+ autoMergeStatus
2086
+ });
2087
+ this.scheduleFlush();
2088
+ });
2075
2089
  on("issue:reconcile-remove", (issueId) => {
2076
2090
  this.removeCard(issueId);
2077
2091
  this.scheduleFlush();
@@ -2237,7 +2251,7 @@ async function executeRun(args) {
2237
2251
  if (isTTY) {
2238
2252
  const { render } = await import("ink");
2239
2253
  const { createElement } = await import("react");
2240
- const { KanbanApp } = await import("./kanban-XCQ6QNOL.js");
2254
+ const { KanbanApp } = await import("./kanban-QQ47VJUY.js");
2241
2255
  const demoConfig = {
2242
2256
  provider: "claude",
2243
2257
  source: "linear",
@@ -2337,7 +2351,7 @@ Add them to your ${shell} and run: source ${shell}`));
2337
2351
  const initialCards = persistence.load();
2338
2352
  persistedCards = initialCards;
2339
2353
  persistence.start();
2340
- const { registerPlanBridge } = await import("./tui-bridge-GGH36LIH.js");
2354
+ const { registerPlanBridge } = await import("./tui-bridge-HVSZNVDO.js");
2341
2355
  const cleanupPlan = registerPlanBridge(merged);
2342
2356
  onBeforeExit = () => {
2343
2357
  persistence.stop();
@@ -2345,7 +2359,7 @@ Add them to your ${shell} and run: source ${shell}`));
2345
2359
  };
2346
2360
  const { render } = await import("ink");
2347
2361
  const { createElement } = await import("react");
2348
- const { KanbanApp } = await import("./kanban-XCQ6QNOL.js");
2362
+ const { KanbanApp } = await import("./kanban-QQ47VJUY.js");
2349
2363
  render(createElement(KanbanApp, { config: merged, initialCards }), { exitOnCtrlC: false });
2350
2364
  }
2351
2365
  await runLoop(merged, {
@@ -2501,7 +2515,7 @@ process.on("unhandledRejection", (err) => {
2501
2515
  }
2502
2516
  process.exit(1);
2503
2517
  });
2504
- import("./detection-2Z6TXYHU.js").then(
2518
+ import("./detection-TGAZED6Q.js").then(
2505
2519
  ({ getVersion: getVersion2 }) => import("./version-D2YFKS7Q.js").then(({ checkForUpdate }) => checkForUpdate(getVersion2()))
2506
2520
  );
2507
2521
  runCli();
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  kanbanEmitter,
4
4
  useKanbanState
5
- } from "./chunk-SOV2YONG.js";
5
+ } from "./chunk-ZHB4S7SP.js";
6
6
  import {
7
7
  resetTitle,
8
8
  startSpinner,
@@ -141,10 +141,14 @@ function Card({
141
141
  "\u2714 ",
142
142
  formatElapsed(card.finishedAt - card.startedAt)
143
143
  ] }),
144
- card.prUrls.length > 0 && /* @__PURE__ */ jsxs(Text, { color: card.merged ? "magenta" : "yellow", dimColor: true, children: [
145
- card.merged ? "PR\u2714" : "PR",
146
- card.ciStatus === "pending" ? "\u23F3" : card.ciStatus === "passing" ? "\u2714" : card.ciStatus === "failing" ? "\u2716" : ""
147
- ] })
144
+ card.prUrls.length > 0 && /* @__PURE__ */ jsx(
145
+ Text,
146
+ {
147
+ color: card.autoMergeStatus === "failed" ? "red" : card.merged || card.autoMergeStatus === "merged" ? "magenta" : "yellow",
148
+ dimColor: true,
149
+ children: card.merged || card.autoMergeStatus === "merged" ? "PR\u2714" : card.autoMergeStatus === "waiting" || card.autoMergeStatus === "merging" ? "PR\u23F3" : card.autoMergeStatus === "failed" ? "PR\u2716" : "PR"
150
+ }
151
+ )
148
152
  ] }) : card.killed ? /* @__PURE__ */ jsx(Text, { color: "red", children: "KILLED" }) : card.skipped ? /* @__PURE__ */ jsx(Text, { color: "gray", children: "SKIPPED" }) : card.hasError && !card.killed && !card.skipped ? /* @__PURE__ */ jsx(Text, { color: "red", children: "FAILED" }) : (
149
153
  // Empty row for backlog and done-without-timing — maintains CARD_HEIGHT
150
154
  /* @__PURE__ */ jsx(Text, { children: " ".repeat(cardWidth) })
@@ -534,7 +538,8 @@ function IssueDetail({
534
538
  const prMetaRow = hasPrMeta ? 1 : 0;
535
539
  const pickerRows = showReviewerPicker ? Math.min((card.availableReviewers ?? []).length + 2, 12) : 0;
536
540
  const ciRow = card.ciStatus ? 1 : 0;
537
- const headerOverhead = 6 + prCount + logFileRow + ciRow + prMetaRow + pickerRows;
541
+ const autoMergeRow = card.autoMergeStatus ? 1 : 0;
542
+ const headerOverhead = 6 + prCount + logFileRow + ciRow + autoMergeRow + prMetaRow + pickerRows;
538
543
  const bodyRows = Math.max(1, terminalRows - headerOverhead);
539
544
  const lines = useMemo(() => processOutputLines(card.outputLog), [card.outputLog]);
540
545
  const startLine = Math.max(0, lines.length - bodyRows - logScrollOffset);
@@ -609,6 +614,16 @@ function IssueDetail({
609
614
  }
610
615
  )
611
616
  ] }),
617
+ card.autoMergeStatus && /* @__PURE__ */ jsxs4(Box4, { marginTop: 0, children: [
618
+ /* @__PURE__ */ jsx4(Text4, { color: "gray", dimColor: true, children: "MERGE: " }),
619
+ /* @__PURE__ */ jsx4(
620
+ Text4,
621
+ {
622
+ color: card.autoMergeStatus === "merged" ? "magenta" : card.autoMergeStatus === "failed" ? "red" : "yellow",
623
+ children: card.autoMergeStatus === "merged" ? `\u2714 merged (${card.prUrls.length} PR${card.prUrls.length > 1 ? "s" : ""})` : card.autoMergeStatus === "failed" ? "\u2716 failed" : card.autoMergeStatus === "merging" ? "\u23F3 merging..." : "\u23F3 waiting for CI"
624
+ }
625
+ )
626
+ ] }),
612
627
  hasPrMeta && /* @__PURE__ */ jsxs4(Box4, { marginTop: 0, flexDirection: "row", children: [
613
628
  cardReviewers.length > 0 ? /* @__PURE__ */ jsxs4(Fragment2, { children: [
614
629
  /* @__PURE__ */ jsx4(Text4, { color: "cyan", dimColor: true, children: "REVIEWERS: " }),
@@ -4,11 +4,11 @@ import {
4
4
  cleanupEventListeners,
5
5
  runDemoLoop,
6
6
  runLoop
7
- } from "./chunk-BI6MR2UP.js";
7
+ } from "./chunk-VVYGYOPG.js";
8
8
  import {
9
9
  WATCH_POLL_INTERVAL_MS
10
- } from "./chunk-YTUZFCU2.js";
11
- import "./chunk-SOV2YONG.js";
10
+ } from "./chunk-YSFHP3A3.js";
11
+ import "./chunk-ZHB4S7SP.js";
12
12
  import "./chunk-ZOVVFU7B.js";
13
13
  import "./chunk-3EOEDL3T.js";
14
14
  import "./chunk-7OCDGYDM.js";
@@ -6,15 +6,15 @@ import {
6
6
  markdownToIssue,
7
7
  parseStructuredOutput,
8
8
  savePlan
9
- } from "./chunk-RZ53EOAY.js";
9
+ } from "./chunk-6ZWVYPR5.js";
10
10
  import {
11
11
  createSource,
12
12
  resolveModels,
13
13
  runWithFallback
14
- } from "./chunk-YTUZFCU2.js";
14
+ } from "./chunk-YSFHP3A3.js";
15
15
  import {
16
16
  kanbanEmitter
17
- } from "./chunk-SOV2YONG.js";
17
+ } from "./chunk-ZHB4S7SP.js";
18
18
  import "./chunk-ZOVVFU7B.js";
19
19
  import "./chunk-3EOEDL3T.js";
20
20
  import "./chunk-7OCDGYDM.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tarcisiopgs/lisa",
3
- "version": "1.40.2",
3
+ "version": "1.42.0",
4
4
  "description": "Autonomous issue resolver",
5
5
  "keywords": [
6
6
  "loop",