@tarcisiopgs/lisa 1.32.0 → 1.33.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.
@@ -30,7 +30,7 @@ import {
30
30
  resolveModels,
31
31
  runValidationCommands,
32
32
  runWithFallback
33
- } from "./chunk-NHC3JG2C.js";
33
+ } from "./chunk-SC222P5D.js";
34
34
  import {
35
35
  divider,
36
36
  error,
@@ -39,7 +39,7 @@ import {
39
39
  log,
40
40
  ok,
41
41
  warn
42
- } from "./chunk-66TB6NMR.js";
42
+ } from "./chunk-XLAY4P45.js";
43
43
  import {
44
44
  appendRawEntry,
45
45
  migrateGuardrails
@@ -4,14 +4,14 @@ import {
4
4
  readContext,
5
5
  resolveModels,
6
6
  runWithFallback
7
- } from "./chunk-NHC3JG2C.js";
7
+ } from "./chunk-SC222P5D.js";
8
8
  import {
9
9
  error,
10
10
  log,
11
11
  normalizeLabels,
12
12
  ok,
13
13
  warn
14
- } from "./chunk-66TB6NMR.js";
14
+ } from "./chunk-XLAY4P45.js";
15
15
 
16
16
  // src/cli/error.ts
17
17
  var CliError = class extends Error {
@@ -153,6 +153,16 @@ function extractCleanText(text2) {
153
153
  }
154
154
 
155
155
  // src/plan/create.ts
156
+ function ensureAcceptanceCriteria(description, criteria) {
157
+ if (!criteria.length) return description;
158
+ if (/- \[ \]/.test(description)) return description;
159
+ const checklist = criteria.map((c) => `- [ ] ${c}`).join("\n");
160
+ return `${description}
161
+
162
+ ## Acceptance Criteria
163
+
164
+ ${checklist}`;
165
+ }
156
166
  async function createPlanIssues(source, config, plan) {
157
167
  if (!source.createIssue) {
158
168
  throw new Error(`Source "${source.name}" does not support createIssue`);
@@ -163,7 +173,7 @@ async function createPlanIssues(source, config, plan) {
163
173
  const createdIds = [];
164
174
  const orderToId = /* @__PURE__ */ new Map();
165
175
  for (const issue of sorted) {
166
- let description = issue.description;
176
+ let description = ensureAcceptanceCriteria(issue.description, issue.acceptanceCriteria);
167
177
  if (issue.dependsOn.length > 0 && !source.linkDependency) {
168
178
  const depRefs = issue.dependsOn.map((depOrder) => {
169
179
  const depId = orderToId.get(depOrder);
@@ -174,33 +184,39 @@ async function createPlanIssues(source, config, plan) {
174
184
  ---
175
185
  _Depends on: ${depRefs}_`;
176
186
  }
177
- const id = await source.createIssue(
178
- {
179
- title: issue.title,
180
- description,
181
- status: config.pick_from,
182
- label: primaryLabel,
183
- order: issue.order,
184
- parentId: plan.sourceIssueId
185
- },
186
- config
187
- );
188
- createdIds.push(id);
189
- orderToId.set(issue.order, id);
190
- ok(`${id}: ${issue.title}`);
191
- if (source.linkDependency && issue.dependsOn.length > 0) {
192
- for (const depOrder of issue.dependsOn) {
193
- const depId = orderToId.get(depOrder);
194
- if (depId) {
195
- try {
196
- await source.linkDependency(id, depId);
197
- } catch (err) {
198
- warn(
199
- `Could not link dependency ${id} \u2192 ${depId}: ${err instanceof Error ? err.message : String(err)}`
200
- );
187
+ try {
188
+ const id = await source.createIssue(
189
+ {
190
+ title: issue.title,
191
+ description,
192
+ status: config.pick_from,
193
+ label: primaryLabel,
194
+ order: issue.order,
195
+ parentId: plan.sourceIssueId
196
+ },
197
+ config
198
+ );
199
+ createdIds.push(id);
200
+ orderToId.set(issue.order, id);
201
+ ok(`${id}: ${issue.title}`);
202
+ if (source.linkDependency && issue.dependsOn.length > 0) {
203
+ for (const depOrder of issue.dependsOn) {
204
+ const depId = orderToId.get(depOrder);
205
+ if (depId) {
206
+ try {
207
+ await source.linkDependency(id, depId);
208
+ } catch (err) {
209
+ warn(
210
+ `Could not link dependency ${id} \u2192 ${depId}: ${err instanceof Error ? err.message : String(err)}`
211
+ );
212
+ }
201
213
  }
202
214
  }
203
215
  }
216
+ } catch (err) {
217
+ warn(
218
+ `Failed to create issue "${issue.title}": ${err instanceof Error ? err.message : String(err)}`
219
+ );
204
220
  }
205
221
  }
206
222
  return createdIds;
@@ -11,7 +11,7 @@ import {
11
11
  normalizeLabels,
12
12
  ok,
13
13
  warn
14
- } from "./chunk-66TB6NMR.js";
14
+ } from "./chunk-XLAY4P45.js";
15
15
  import {
16
16
  appendEntry,
17
17
  buildGuardrailsSection,
@@ -772,6 +772,7 @@ function registerBellListeners(bellEnabled) {
772
772
  function useKanbanState(bellEnabled, initialCards = []) {
773
773
  const [cards, setCards] = useState(initialCards);
774
774
  const [isEmpty, setIsEmpty] = useState(false);
775
+ const [isFetching, setIsFetching] = useState(initialCards.length === 0);
775
776
  const [isWatching, setIsWatching] = useState(false);
776
777
  const [isWatchPrompt, setIsWatchPrompt] = useState(false);
777
778
  const [workComplete, setWorkComplete] = useState(
@@ -780,6 +781,7 @@ function useKanbanState(bellEnabled, initialCards = []) {
780
781
  const [modelInUse, setModelInUse] = useState(null);
781
782
  useEffect(() => {
782
783
  const onQueued = (issue) => {
784
+ setIsFetching(false);
783
785
  setCards((prev) => {
784
786
  if (prev.some((c) => c.id === issue.id)) return prev;
785
787
  const maxOrder = prev.reduce((max, c) => Math.max(max, c.queueOrder ?? 0), 0);
@@ -933,10 +935,16 @@ function useKanbanState(bellEnabled, initialCards = []) {
933
935
  kanbanEmitter.on("issue:output", onOutput);
934
936
  const onModelChanged = (model) => setModelInUse(model);
935
937
  kanbanEmitter.on("provider:model-changed", onModelChanged);
936
- const onEmpty = () => setIsEmpty(true);
938
+ const onEmpty = () => {
939
+ setIsEmpty(true);
940
+ setIsFetching(false);
941
+ };
937
942
  const onResumed = () => setIsEmpty(false);
938
943
  const onComplete = (data) => setWorkComplete(data);
939
- const onWatching = () => setIsWatching(true);
944
+ const onWatching = () => {
945
+ setIsWatching(true);
946
+ setIsFetching(false);
947
+ };
940
948
  const onWatchResume = () => setIsWatching(false);
941
949
  const onWatchPrompt = () => {
942
950
  setIsWatchPrompt(true);
@@ -992,7 +1000,7 @@ function useKanbanState(bellEnabled, initialCards = []) {
992
1000
  }
993
1001
  }
994
1002
  }, []);
995
- return { cards, isEmpty, isWatching, isWatchPrompt, workComplete, modelInUse };
1003
+ return { cards, isEmpty, isFetching, isWatching, isWatchPrompt, workComplete, modelInUse };
996
1004
  }
997
1005
 
998
1006
  export {
package/dist/index.js CHANGED
@@ -7,7 +7,7 @@ import {
7
7
  parseStructuredOutput,
8
8
  runPlanWizard,
9
9
  savePlan
10
- } from "./chunk-K2ILRYXS.js";
10
+ } from "./chunk-6XC7GQUI.js";
11
11
  import {
12
12
  detectDefaultBranch,
13
13
  detectGitRepos,
@@ -36,7 +36,7 @@ import {
36
36
  runLoop,
37
37
  saveConfig,
38
38
  validateConfig
39
- } from "./chunk-AAWXKEV7.js";
39
+ } from "./chunk-23Z5BBRT.js";
40
40
  import {
41
41
  buildContextMdBlock,
42
42
  createProvider,
@@ -48,7 +48,7 @@ import {
48
48
  readContext,
49
49
  resolveModels,
50
50
  runWithFallback
51
- } from "./chunk-NHC3JG2C.js";
51
+ } from "./chunk-SC222P5D.js";
52
52
  import {
53
53
  banner,
54
54
  error,
@@ -58,7 +58,7 @@ import {
58
58
  setLogLevel,
59
59
  setOutputMode,
60
60
  updateNotice
61
- } from "./chunk-66TB6NMR.js";
61
+ } from "./chunk-XLAY4P45.js";
62
62
  import "./chunk-3EOEDL3T.js";
63
63
  import {
64
64
  getKanbanStatePath,
@@ -1544,7 +1544,7 @@ async function reviewAndCreate(plan2, planPath, opts) {
1544
1544
  log("Run `lisa run` when ready.");
1545
1545
  return;
1546
1546
  }
1547
- const { runLoop: runLoop2 } = await import("./loop-PXUNTCQS.js");
1547
+ const { runLoop: runLoop2 } = await import("./loop-XEJHKZHO.js");
1548
1548
  await runLoop2(config2, {
1549
1549
  once: false,
1550
1550
  watch: false,
@@ -1908,7 +1908,7 @@ async function executeRun(args) {
1908
1908
  if (isTTY) {
1909
1909
  const { render } = await import("ink");
1910
1910
  const { createElement } = await import("react");
1911
- const { KanbanApp } = await import("./kanban-F27DQLKJ.js");
1911
+ const { KanbanApp } = await import("./kanban-X4OR4ZFI.js");
1912
1912
  const demoConfig = {
1913
1913
  provider: "claude",
1914
1914
  source: "linear",
@@ -2008,7 +2008,7 @@ Add them to your ${shell} and run: source ${shell}`));
2008
2008
  const initialCards = persistence.load();
2009
2009
  persistedCards = initialCards;
2010
2010
  persistence.start();
2011
- const { registerPlanBridge } = await import("./tui-bridge-WKKIHWJT.js");
2011
+ const { registerPlanBridge } = await import("./tui-bridge-G6BBFZFH.js");
2012
2012
  const cleanupPlan = registerPlanBridge(merged);
2013
2013
  onBeforeExit = () => {
2014
2014
  persistence.stop();
@@ -2016,7 +2016,7 @@ Add them to your ${shell} and run: source ${shell}`));
2016
2016
  };
2017
2017
  const { render } = await import("ink");
2018
2018
  const { createElement } = await import("react");
2019
- const { KanbanApp } = await import("./kanban-F27DQLKJ.js");
2019
+ const { KanbanApp } = await import("./kanban-X4OR4ZFI.js");
2020
2020
  render(createElement(KanbanApp, { config: merged, initialCards }), { exitOnCtrlC: false });
2021
2021
  }
2022
2022
  await runLoop(merged, {
@@ -5,7 +5,7 @@ import {
5
5
  import {
6
6
  kanbanEmitter,
7
7
  useKanbanState
8
- } from "./chunk-66TB6NMR.js";
8
+ } from "./chunk-XLAY4P45.js";
9
9
  import {
10
10
  resetTitle,
11
11
  startSpinner,
@@ -18,6 +18,7 @@ import { useEffect as useEffect5, useState as useState6 } from "react";
18
18
 
19
19
  // src/ui/board.tsx
20
20
  import { Box as Box3, Text as Text3 } from "ink";
21
+ import Spinner2 from "ink-spinner";
21
22
 
22
23
  // src/ui/column.tsx
23
24
  import { Box as Box2, Text as Text2 } from "ink";
@@ -257,6 +258,7 @@ function Board({
257
258
  columns,
258
259
  labels,
259
260
  isEmpty,
261
+ isFetching = false,
260
262
  isWatching = false,
261
263
  isWatchPrompt = false,
262
264
  workComplete,
@@ -265,6 +267,28 @@ function Board({
265
267
  paused = false
266
268
  }) {
267
269
  const { backlog, inProgress, done } = columns;
270
+ if (isFetching) {
271
+ return /* @__PURE__ */ jsx3(Box3, { flexGrow: 1, alignItems: "center", justifyContent: "center", children: /* @__PURE__ */ jsxs3(
272
+ Box3,
273
+ {
274
+ flexDirection: "column",
275
+ borderStyle: "single",
276
+ borderColor: "yellow",
277
+ paddingX: 3,
278
+ paddingY: 1,
279
+ children: [
280
+ /* @__PURE__ */ jsxs3(Box3, { flexDirection: "row", children: [
281
+ /* @__PURE__ */ jsx3(Text3, { color: "yellow", children: /* @__PURE__ */ jsx3(Spinner2, { type: "dots" }) }),
282
+ /* @__PURE__ */ jsx3(Text3, { color: "yellow", bold: true, children: " FETCHING ISSUES..." })
283
+ ] }),
284
+ /* @__PURE__ */ jsx3(Box3, { height: 1 }),
285
+ /* @__PURE__ */ jsx3(Text3, { color: "white", dimColor: true, children: "Querying the issue tracker for matching items." }),
286
+ /* @__PURE__ */ jsx3(Box3, { height: 1 }),
287
+ /* @__PURE__ */ jsx3(Text3, { color: "gray", dimColor: true, children: "Press [q] to quit" })
288
+ ]
289
+ }
290
+ ) });
291
+ }
268
292
  if (isWatching) {
269
293
  return /* @__PURE__ */ jsx3(Box3, { flexGrow: 1, alignItems: "center", justifyContent: "center", children: /* @__PURE__ */ jsxs3(
270
294
  Box3,
@@ -378,7 +402,7 @@ function Board({
378
402
  // src/ui/detail.tsx
379
403
  import { exec } from "child_process";
380
404
  import { Box as Box4, Text as Text4, useInput } from "ink";
381
- import Spinner2 from "ink-spinner";
405
+ import Spinner3 from "ink-spinner";
382
406
  import { useEffect as useEffect3, useMemo, useRef, useState as useState3 } from "react";
383
407
 
384
408
  // src/output/line-color.ts
@@ -535,7 +559,7 @@ function IssueDetail({ card, onBack, reviewers, assignees }) {
535
559
  ] }),
536
560
  /* @__PURE__ */ jsxs4(Box4, { flexDirection: "row", children: [
537
561
  isRunning && elapsedDisplay && /* @__PURE__ */ jsxs4(Box4, { flexDirection: "row", marginRight: 2, children: [
538
- /* @__PURE__ */ jsx4(Text4, { color: "yellow", children: /* @__PURE__ */ jsx4(Spinner2, { type: "dots" }) }),
562
+ /* @__PURE__ */ jsx4(Text4, { color: "yellow", children: /* @__PURE__ */ jsx4(Spinner3, { type: "dots" }) }),
539
563
  /* @__PURE__ */ jsx4(Text4, { color: "yellow", bold: true, children: ` ${elapsedDisplay}` })
540
564
  ] }),
541
565
  isPausedInProgress && elapsedDisplay && /* @__PURE__ */ jsxs4(Box4, { flexDirection: "row", marginRight: 2, children: [
@@ -575,7 +599,7 @@ function IssueDetail({ card, onBack, reviewers, assignees }) {
575
599
  !userScrolled && totalLines > bodyRows && /* @__PURE__ */ jsx4(Text4, { color: "gray", dimColor: true, children: "live" })
576
600
  ] }),
577
601
  /* @__PURE__ */ jsx4(Box4, { height: bodyRows, flexDirection: "column", overflow: "hidden", children: card.outputLog.length === 0 ? /* @__PURE__ */ jsxs4(Box4, { flexDirection: "row", marginTop: 1, children: [
578
- /* @__PURE__ */ jsx4(Text4, { color: "yellow", children: /* @__PURE__ */ jsx4(Spinner2, { type: "dots" }) }),
602
+ /* @__PURE__ */ jsx4(Text4, { color: "yellow", children: /* @__PURE__ */ jsx4(Spinner3, { type: "dots" }) }),
579
603
  /* @__PURE__ */ jsx4(Text4, { color: "gray", dimColor: true, children: " Waiting for provider output..." })
580
604
  ] }) : visibleLines.map((line, i) => {
581
605
  const color = logLineColor(line);
@@ -591,7 +615,7 @@ function IssueDetail({ card, onBack, reviewers, assignees }) {
591
615
 
592
616
  // src/ui/plan-chat.tsx
593
617
  import { Box as Box5, Text as Text5, useInput as useInput2 } from "ink";
594
- import Spinner3 from "ink-spinner";
618
+ import Spinner4 from "ink-spinner";
595
619
  import { useEffect as useEffect4, useState as useState4 } from "react";
596
620
  import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
597
621
  var SIDEBAR_TOTAL_WIDTH = 30;
@@ -718,7 +742,7 @@ function PlanChat({ messages, isThinking, onSend, onCancel }) {
718
742
  );
719
743
  }),
720
744
  isThinking && /* @__PURE__ */ jsxs5(Box5, { flexDirection: "row", marginTop: 0, children: [
721
- /* @__PURE__ */ jsx5(Text5, { color: "yellow", children: /* @__PURE__ */ jsx5(Spinner3, { type: "dots" }) }),
745
+ /* @__PURE__ */ jsx5(Text5, { color: "yellow", children: /* @__PURE__ */ jsx5(Spinner4, { type: "dots" }) }),
722
746
  /* @__PURE__ */ jsx5(Text5, { color: "gray", dimColor: true, children: " Analyzing..." })
723
747
  ] })
724
748
  ] }),
@@ -1062,10 +1086,7 @@ function Sidebar({
1062
1086
  import { jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
1063
1087
  function KanbanApp({ config, initialCards = [] }) {
1064
1088
  const { exit } = useApp();
1065
- const { cards, isEmpty, isWatching, isWatchPrompt, workComplete, modelInUse } = useKanbanState(
1066
- config.bell ?? true,
1067
- initialCards
1068
- );
1089
+ const { cards, isEmpty, isFetching, isWatching, isWatchPrompt, workComplete, modelInUse } = useKanbanState(config.bell ?? true, initialCards);
1069
1090
  const { rows } = useTerminalSize();
1070
1091
  const [activeView, setActiveView] = useState6("board");
1071
1092
  const [activeColIndex, setActiveColIndex] = useState6(0);
@@ -1185,7 +1206,7 @@ function KanbanApp({ config, initialCards = [] }) {
1185
1206
  }, [cards, selectedCardId, activeView]);
1186
1207
  const selectedCard = activeView === "detail" && selectedCardId ? cards.find((c) => c.id === selectedCardId) ?? null : null;
1187
1208
  async function handleMergeRequest(card) {
1188
- const { checkPrCiStatus } = await import("./merge-LRFZXFV2.js");
1209
+ const { checkPrCiStatus } = await import("./merge-CFQO7VU4.js");
1189
1210
  const prUrl = card.prUrls[0];
1190
1211
  const ciStatus = await checkPrCiStatus(prUrl);
1191
1212
  if (ciStatus === "passing" || ciStatus === "unknown") {
@@ -1198,7 +1219,7 @@ function KanbanApp({ config, initialCards = [] }) {
1198
1219
  const card = cards.find((c) => c.id === issueId);
1199
1220
  if (!card || card.prUrls.length === 0) return;
1200
1221
  setMerging(issueId);
1201
- const { mergePr } = await import("./merge-LRFZXFV2.js");
1222
+ const { mergePr } = await import("./merge-CFQO7VU4.js");
1202
1223
  let allSuccess = true;
1203
1224
  for (const prUrl of card.prUrls) {
1204
1225
  const result = await mergePr(prUrl);
@@ -1413,6 +1434,7 @@ Merge failed: ${result.error}
1413
1434
  let sidebarMode = "board";
1414
1435
  if (isWatchPrompt) sidebarMode = "watch-prompt";
1415
1436
  else if (isWatching) sidebarMode = "watching";
1437
+ else if (isFetching && activeView === "board") sidebarMode = "empty";
1416
1438
  else if (isEmpty && activeView === "board" && cards.length === 0) sidebarMode = "empty";
1417
1439
  else if (isEmpty && activeView === "board" && cards.length > 0) sidebarMode = "idle";
1418
1440
  else if (activeView === "plan-chat") sidebarMode = "plan-chat";
@@ -1496,6 +1518,7 @@ Merge failed: ${result.error}
1496
1518
  columns: { backlog, inProgress, done },
1497
1519
  labels,
1498
1520
  isEmpty,
1521
+ isFetching,
1499
1522
  isWatching,
1500
1523
  isWatchPrompt,
1501
1524
  workComplete,
@@ -3,11 +3,11 @@ import {
3
3
  checkoutBaseBranches,
4
4
  runDemoLoop,
5
5
  runLoop
6
- } from "./chunk-AAWXKEV7.js";
6
+ } from "./chunk-23Z5BBRT.js";
7
7
  import {
8
8
  WATCH_POLL_INTERVAL_MS
9
- } from "./chunk-NHC3JG2C.js";
10
- import "./chunk-66TB6NMR.js";
9
+ } from "./chunk-SC222P5D.js";
10
+ import "./chunk-XLAY4P45.js";
11
11
  import "./chunk-3EOEDL3T.js";
12
12
  import "./chunk-7OCDGYDM.js";
13
13
  import "./chunk-72CYGBT4.js";
@@ -71,7 +71,9 @@ async function mergePr(prUrl) {
71
71
  }
72
72
  async function mergeGitHubPr(prUrl) {
73
73
  try {
74
- await execa("gh", ["pr", "merge", prUrl, "--delete-branch"], { timeout: 3e4 });
74
+ await execa("gh", ["pr", "merge", prUrl, "--squash", "--delete-branch"], {
75
+ timeout: 3e4
76
+ });
75
77
  return { success: true };
76
78
  } catch (err) {
77
79
  return { success: false, error: formatError(err) };
@@ -6,19 +6,19 @@ import {
6
6
  markdownToIssue,
7
7
  parseStructuredOutput,
8
8
  savePlan
9
- } from "./chunk-K2ILRYXS.js";
9
+ } from "./chunk-6XC7GQUI.js";
10
10
  import {
11
11
  createSource,
12
12
  resolveModels,
13
13
  runWithFallback
14
- } from "./chunk-NHC3JG2C.js";
14
+ } from "./chunk-SC222P5D.js";
15
15
  import {
16
16
  error,
17
17
  kanbanEmitter,
18
18
  log,
19
19
  ok,
20
20
  warn
21
- } from "./chunk-66TB6NMR.js";
21
+ } from "./chunk-XLAY4P45.js";
22
22
  import "./chunk-3EOEDL3T.js";
23
23
  import "./chunk-7OCDGYDM.js";
24
24
  import "./chunk-72CYGBT4.js";
@@ -133,6 +133,9 @@ async function handleApproval(config, issues, goal) {
133
133
  } catch (err) {
134
134
  warn(`Could not refresh kanban: ${err instanceof Error ? err.message : String(err)}`);
135
135
  }
136
+ if (createdIds.length > 0) {
137
+ kanbanEmitter.emit("loop:run");
138
+ }
136
139
  }
137
140
  function buildChatPrompt(goal, config, chatHistory) {
138
141
  const basePrompt = buildPlanningPrompt(goal, config);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tarcisiopgs/lisa",
3
- "version": "1.32.0",
3
+ "version": "1.33.0",
4
4
  "description": "Autonomous issue resolver",
5
5
  "keywords": [
6
6
  "loop",