@tarcisiopgs/lisa 0.7.0 → 0.8.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 (3) hide show
  1. package/README.md +38 -13
  2. package/dist/index.js +84 -49
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -89,21 +89,21 @@ Worktree mode is ideal when you want to keep working in the repo while lisa reso
89
89
 
90
90
  Config lives in `.lisa/config.yaml`:
91
91
 
92
+ **Linear:**
92
93
  ```yaml
93
94
  provider: claude
94
95
  source: linear
95
96
  workflow: branch
96
97
 
97
98
  source_config:
98
- team: Internal
99
- project: Zenixx
99
+ team: Engineering
100
+ project: Web App
100
101
  label: ready
101
- initial_status: Todo
102
- active_status: In Progress
103
- done_status: In Review
102
+ pick_from: Todo
103
+ in_progress: In Progress
104
+ done: In Review
104
105
 
105
106
  github: cli
106
-
107
107
  workspace: .
108
108
  repos:
109
109
  - name: app
@@ -119,16 +119,41 @@ logs:
119
119
  format: text
120
120
  ```
121
121
 
122
+ **Trello:**
123
+ ```yaml
124
+ provider: claude
125
+ source: trello
126
+ workflow: branch
127
+
128
+ source_config:
129
+ board: Product
130
+ pick_from: Backlog
131
+ label: ready
132
+ in_progress: In Progress
133
+ done: Code Review
134
+
135
+ github: cli
136
+ workspace: .
137
+
138
+ loop:
139
+ cooldown: 10
140
+ max_sessions: 0
141
+
142
+ logs:
143
+ dir: .lisa/logs
144
+ format: text
145
+ ```
146
+
122
147
  ### Source-specific fields
123
148
 
124
149
  | Field | Linear | Trello |
125
150
  |-------|--------|--------|
126
- | `team` | Team name | Board name |
127
- | `project` | Project name | List name (source column) |
151
+ | `team` / `board` | Team name | Board name |
152
+ | `project` | Project name | |
153
+ | `pick_from` | Status to pick issues from (e.g. Todo) | List to pick cards from (e.g. Backlog) |
128
154
  | `label` | Label to filter issues | Label to filter cards |
129
- | `initial_status` | Source status (e.g. Todo) | Same as `project` |
130
- | `active_status` | In-progress status (e.g. In Progress) | In-progress column |
131
- | `done_status` | Destination status (e.g. In Review) | Destination column (e.g. Code Review) |
155
+ | `in_progress` | In-progress status (e.g. In Progress) | In-progress column |
156
+ | `done` | Destination status (e.g. In Review) | Destination column (e.g. Code Review) |
132
157
 
133
158
  CLI flags override config values:
134
159
 
@@ -139,8 +164,8 @@ lisa run --provider gemini --label "urgent"
139
164
  ## How It Works
140
165
 
141
166
  1. **Fetch** — Calls the Linear GraphQL API or Trello REST API to get the next issue matching the configured label, team, and project. Issues are sorted by priority.
142
- 2. **Activate** — Moves the issue to the configured `active_status` (e.g. "In Progress") so your team can see it's being worked on.
167
+ 2. **Activate** — Moves the issue to the configured `in_progress` status (e.g. "In Progress") so your team can see it's being worked on.
143
168
  3. **Implement** — Builds a prompt with the issue context and sends it to the AI coding agent. In branch mode, the agent creates a branch and works in the current checkout. In worktree mode, lisa creates an isolated worktree first.
144
169
  4. **PR** — Creates a pull request via the GitHub API (CLI or token) referencing the original issue. In multi-repo workspaces, the correct repo is detected automatically.
145
- 5. **Update** — Moves the issue to the configured `done_status` and removes the pickup label via the source API.
170
+ 5. **Update** — Moves the issue to the configured `done` status and removes the pickup label via the source API.
146
171
  6. **Loop** — Waits `cooldown` seconds, then picks the next issue. Repeats until no issues remain or the limit is reached.
package/dist/index.js CHANGED
@@ -21,9 +21,9 @@ var DEFAULT_CONFIG = {
21
21
  team: "",
22
22
  project: "",
23
23
  label: "",
24
- initial_status: "",
25
- active_status: "",
26
- done_status: ""
24
+ pick_from: "",
25
+ in_progress: "",
26
+ done: ""
27
27
  },
28
28
  github: "cli",
29
29
  workflow: "branch",
@@ -52,12 +52,24 @@ function loadConfig(cwd = process.cwd()) {
52
52
  }
53
53
  const raw = readFileSync(configPath, "utf-8");
54
54
  const parsed = parse(raw);
55
+ const rawSource = parsed.source_config ?? {};
56
+ const sourceConfig = {
57
+ team: rawSource.team ?? rawSource.board ?? "",
58
+ project: rawSource.project ?? rawSource.list ?? rawSource.pick_from ?? "",
59
+ label: rawSource.label ?? "",
60
+ pick_from: rawSource.pick_from ?? rawSource.initial_status ?? "",
61
+ in_progress: rawSource.in_progress ?? rawSource.active_status ?? "",
62
+ done: rawSource.done ?? rawSource.done_status ?? ""
63
+ };
64
+ if (parsed.source === "trello" && !sourceConfig.pick_from) {
65
+ sourceConfig.pick_from = sourceConfig.project;
66
+ }
55
67
  const config2 = {
56
68
  ...DEFAULT_CONFIG,
57
69
  ...parsed,
58
- source_config: { ...DEFAULT_CONFIG.source_config, ...parsed.source_config },
59
- loop: { ...DEFAULT_CONFIG.loop, ...parsed.loop },
60
- logs: { ...DEFAULT_CONFIG.logs, ...parsed.logs }
70
+ source_config: sourceConfig,
71
+ loop: { ...DEFAULT_CONFIG.loop, ...parsed.loop ?? {} },
72
+ logs: { ...DEFAULT_CONFIG.logs, ...parsed.logs ?? {} }
61
73
  };
62
74
  if (!config2.base_branch) config2.base_branch = "main";
63
75
  for (const repo of config2.repos) {
@@ -71,7 +83,10 @@ function saveConfig(config2, cwd = process.cwd()) {
71
83
  if (!existsSync(dir)) {
72
84
  mkdirSync(dir, { recursive: true });
73
85
  }
74
- writeFileSync(configPath, stringify(config2), "utf-8");
86
+ const sc = config2.source_config;
87
+ const sourceYaml = config2.source === "trello" ? { board: sc.team, pick_from: sc.pick_from || sc.project, label: sc.label, in_progress: sc.in_progress, done: sc.done } : { team: sc.team, project: sc.project, label: sc.label, pick_from: sc.pick_from, in_progress: sc.in_progress, done: sc.done };
88
+ const output = { ...config2, source_config: sourceYaml };
89
+ writeFileSync(configPath, stringify(output), "utf-8");
75
90
  }
76
91
  function mergeWithFlags(config2, flags) {
77
92
  const merged = { ...config2 };
@@ -585,7 +600,7 @@ var LinearSource = class {
585
600
  teamName: config2.team,
586
601
  projectName: config2.project,
587
602
  labelName: config2.label,
588
- statusName: config2.initial_status
603
+ statusName: config2.pick_from
589
604
  }
590
605
  );
591
606
  const issues = data.issues.nodes;
@@ -931,6 +946,13 @@ async function findBranchByIssueId(repoRoot, issueId) {
931
946
  ], { cwd: repoRoot });
932
947
  const remoteMatch = remote.split("\n").map((b) => b.trim()).filter(Boolean).find((b) => b.toLowerCase().includes(needle));
933
948
  if (remoteMatch) return remoteMatch.replace("origin/", "");
949
+ const { stdout: lsRemote } = await execa2("git", [
950
+ "ls-remote",
951
+ "--heads",
952
+ "origin"
953
+ ], { cwd: repoRoot });
954
+ const lsMatch = lsRemote.split("\n").map((l) => l.trim()).filter(Boolean).map((l) => l.split(" ")[1]?.replace("refs/heads/", "") ?? "").find((b) => b.toLowerCase().includes(needle));
955
+ if (lsMatch) return lsMatch;
934
956
  return void 0;
935
957
  }
936
958
  function determineRepoPath(repos, issue, workspace) {
@@ -995,11 +1017,11 @@ async function runLoop(config2, opts) {
995
1017
  }
996
1018
  ok(`Picked up: ${issue.id} \u2014 ${issue.title}`);
997
1019
  try {
998
- const activeStatus = config2.source_config.active_status;
999
- await source.updateStatus(issue.id, activeStatus);
1000
- ok(`Moved ${issue.id} to "${activeStatus}"`);
1020
+ const inProgress = config2.source_config.in_progress;
1021
+ await source.updateStatus(issue.id, inProgress);
1022
+ ok(`Moved ${issue.id} to "${inProgress}"`);
1001
1023
  } catch (err) {
1002
- warn(`Failed to update active status: ${err instanceof Error ? err.message : String(err)}`);
1024
+ warn(`Failed to update status: ${err instanceof Error ? err.message : String(err)}`);
1003
1025
  }
1004
1026
  const prUrl = config2.workflow === "worktree" ? await runWorktreeSession(config2, issue, logFile, session) : await runBranchSession(config2, issue, logFile, session);
1005
1027
  if (prUrl) {
@@ -1011,7 +1033,7 @@ async function runLoop(config2, opts) {
1011
1033
  }
1012
1034
  }
1013
1035
  try {
1014
- const doneStatus = config2.source_config.done_status;
1036
+ const doneStatus = config2.source_config.done;
1015
1037
  await source.updateStatus(issue.id, doneStatus);
1016
1038
  ok(`Updated ${issue.id} status to "${doneStatus}"`);
1017
1039
  } catch (err) {
@@ -1249,14 +1271,20 @@ var status = defineCommand({
1249
1271
  async run() {
1250
1272
  banner();
1251
1273
  const config2 = loadConfig();
1274
+ const isLinear = config2.source === "linear";
1252
1275
  console.log(pc2.cyan("Configuration:"));
1253
- console.log(` Provider: ${pc2.bold(config2.provider)}`);
1254
- console.log(` Source: ${pc2.bold(config2.source)}`);
1255
- console.log(` Workflow: ${pc2.bold(config2.workflow)}`);
1256
- console.log(` Label: ${pc2.bold(config2.source_config.label)}`);
1257
- console.log(` Team: ${pc2.bold(config2.source_config.team)}`);
1258
- console.log(` Project: ${pc2.bold(config2.source_config.project)}`);
1259
- console.log(` Logs: ${pc2.dim(config2.logs.dir)}`);
1276
+ console.log(` Provider: ${pc2.bold(config2.provider)}`);
1277
+ console.log(` Source: ${pc2.bold(config2.source)}`);
1278
+ console.log(` Workflow: ${pc2.bold(config2.workflow)}`);
1279
+ console.log(` Label: ${pc2.bold(config2.source_config.label)}`);
1280
+ console.log(` ${isLinear ? "Team" : "Board"}: ${pc2.bold(config2.source_config.team)}`);
1281
+ if (isLinear) {
1282
+ console.log(` Project: ${pc2.bold(config2.source_config.project)}`);
1283
+ }
1284
+ console.log(` Pick from: ${pc2.bold(config2.source_config.pick_from)}`);
1285
+ console.log(` In progress: ${pc2.bold(config2.source_config.in_progress)}`);
1286
+ console.log(` Done: ${pc2.bold(config2.source_config.done)}`);
1287
+ console.log(` Logs: ${pc2.dim(config2.logs.dir)}`);
1260
1288
  const { readdirSync: readdirSync2, existsSync: existsSync5 } = await import("fs");
1261
1289
  if (existsSync5(config2.logs.dir)) {
1262
1290
  const logs = readdirSync2(config2.logs.dir).filter((f) => f.endsWith(".log"));
@@ -1344,57 +1372,64 @@ Then run: ${pc2.cyan(`source ${shell}`)}`
1344
1372
  }
1345
1373
  const githubMethod = await detectGitHubMethod();
1346
1374
  const teamAnswer = await clack.text({
1347
- message: source === "linear" ? "Linear team name?" : "Trello board name?"
1375
+ message: source === "linear" ? "Team?" : "Board?"
1348
1376
  });
1349
1377
  if (clack.isCancel(teamAnswer)) return process.exit(0);
1350
1378
  const team = teamAnswer;
1351
- const projectAnswer = await clack.text({
1352
- message: source === "linear" ? "Project name?" : "Trello list name?"
1353
- });
1354
- if (clack.isCancel(projectAnswer)) return process.exit(0);
1355
- const project = projectAnswer;
1356
1379
  const labelAnswer = await clack.text({
1357
1380
  message: "Label to pick up?",
1358
1381
  initialValue: "ready"
1359
1382
  });
1360
1383
  if (clack.isCancel(labelAnswer)) return process.exit(0);
1361
1384
  const label = labelAnswer;
1362
- let initialStatus;
1363
- let activeStatus;
1364
- let doneStatus;
1385
+ let project;
1386
+ let pickFrom;
1387
+ let inProgress;
1388
+ let done;
1365
1389
  if (source === "trello") {
1366
- initialStatus = project;
1367
- const activeAnswer = await clack.text({
1368
- message: "Column while Lisa is working?",
1390
+ const pickFromAnswer = await clack.text({
1391
+ message: "Pick up cards from which list?",
1392
+ initialValue: "Backlog"
1393
+ });
1394
+ if (clack.isCancel(pickFromAnswer)) return process.exit(0);
1395
+ pickFrom = pickFromAnswer;
1396
+ project = pickFrom;
1397
+ const inProgressAnswer = await clack.text({
1398
+ message: "Move to which column while working?",
1369
1399
  initialValue: "In Progress"
1370
1400
  });
1371
- if (clack.isCancel(activeAnswer)) return process.exit(0);
1372
- activeStatus = activeAnswer;
1401
+ if (clack.isCancel(inProgressAnswer)) return process.exit(0);
1402
+ inProgress = inProgressAnswer;
1373
1403
  const doneAnswer = await clack.text({
1374
- message: "Column after PR is opened?",
1404
+ message: "Move to which column after PR?",
1375
1405
  initialValue: "Code Review"
1376
1406
  });
1377
1407
  if (clack.isCancel(doneAnswer)) return process.exit(0);
1378
- doneStatus = doneAnswer;
1408
+ done = doneAnswer;
1379
1409
  } else {
1380
- const statusAnswer = await clack.text({
1381
- message: "Source status (pick issues from)?",
1410
+ const projectAnswer = await clack.text({
1411
+ message: "Project?"
1412
+ });
1413
+ if (clack.isCancel(projectAnswer)) return process.exit(0);
1414
+ project = projectAnswer;
1415
+ const pickFromAnswer = await clack.text({
1416
+ message: "Pick up issues from which status?",
1382
1417
  initialValue: "Backlog"
1383
1418
  });
1384
- if (clack.isCancel(statusAnswer)) return process.exit(0);
1385
- initialStatus = statusAnswer;
1386
- const activeAnswer = await clack.text({
1387
- message: "Status while Lisa is working?",
1419
+ if (clack.isCancel(pickFromAnswer)) return process.exit(0);
1420
+ pickFrom = pickFromAnswer;
1421
+ const inProgressAnswer = await clack.text({
1422
+ message: "Move to which status while working?",
1388
1423
  initialValue: "In Progress"
1389
1424
  });
1390
- if (clack.isCancel(activeAnswer)) return process.exit(0);
1391
- activeStatus = activeAnswer;
1425
+ if (clack.isCancel(inProgressAnswer)) return process.exit(0);
1426
+ inProgress = inProgressAnswer;
1392
1427
  const doneAnswer = await clack.text({
1393
- message: "Status after PR is opened?",
1428
+ message: "Move to which status after PR?",
1394
1429
  initialValue: "In Review"
1395
1430
  });
1396
1431
  if (clack.isCancel(doneAnswer)) return process.exit(0);
1397
- doneStatus = doneAnswer;
1432
+ done = doneAnswer;
1398
1433
  }
1399
1434
  const workflowAnswer = await clack.select({
1400
1435
  message: "How should Lisa work on issues?",
@@ -1445,9 +1480,9 @@ Then run: ${pc2.cyan(`source ${shell}`)}`
1445
1480
  team,
1446
1481
  project,
1447
1482
  label,
1448
- initial_status: initialStatus,
1449
- active_status: activeStatus,
1450
- done_status: doneStatus
1483
+ pick_from: pickFrom,
1484
+ in_progress: inProgress,
1485
+ done
1451
1486
  },
1452
1487
  github: githubMethod,
1453
1488
  workflow,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tarcisiopgs/lisa",
3
- "version": "0.7.0",
3
+ "version": "0.8.0",
4
4
  "description": "Autonomous issue resolver — AI agent loop for Linear/Trello",
5
5
  "type": "module",
6
6
  "bin": {