@tarcisiopgs/lisa 1.26.2 → 1.28.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 +21 -5
- package/dist/chunk-2TW2MJXF.js +116 -0
- package/dist/{chunk-CDI22S63.js → chunk-3EOEDL3T.js} +2 -2
- package/dist/{chunk-AGYOJQBR.js → chunk-42NKASE3.js} +8 -106
- package/dist/{chunk-235DMOXJ.js → chunk-5N4BWHIT.js} +186 -116
- package/dist/chunk-FCEUJ7VK.js +407 -0
- package/dist/chunk-UXVSQQID.js +3924 -0
- package/dist/chunk-W73XGHD4.js +3059 -0
- package/dist/{detection-OWEDBW7B.js → detection-JT7HSKSX.js} +2 -1
- package/dist/{guardrails-6IG2C4KJ.js → guardrails-IX3VVUO5.js} +1 -1
- package/dist/index.js +1474 -7340
- package/dist/{kanban-PSOTFEQI.js → kanban-2WMA5VPQ.js} +551 -116
- package/dist/loop-KNJIRK7T.js +21 -0
- package/dist/tui-bridge-DCC4JAPM.js +164 -0
- package/package.json +5 -4
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
checkoutBaseBranches,
|
|
4
|
+
runDemoLoop,
|
|
5
|
+
runLoop
|
|
6
|
+
} from "./chunk-W73XGHD4.js";
|
|
7
|
+
import {
|
|
8
|
+
WATCH_POLL_INTERVAL_MS
|
|
9
|
+
} from "./chunk-UXVSQQID.js";
|
|
10
|
+
import "./chunk-5N4BWHIT.js";
|
|
11
|
+
import "./chunk-3EOEDL3T.js";
|
|
12
|
+
import "./chunk-7OCDGYDM.js";
|
|
13
|
+
import "./chunk-72CYGBT4.js";
|
|
14
|
+
import "./chunk-2TW2MJXF.js";
|
|
15
|
+
import "./chunk-DGL33SDZ.js";
|
|
16
|
+
export {
|
|
17
|
+
WATCH_POLL_INTERVAL_MS,
|
|
18
|
+
checkoutBaseBranches,
|
|
19
|
+
runDemoLoop,
|
|
20
|
+
runLoop
|
|
21
|
+
};
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
buildPlanningPrompt,
|
|
4
|
+
createPlanIssues,
|
|
5
|
+
issueToMarkdown,
|
|
6
|
+
markdownToIssue,
|
|
7
|
+
parsePlanResponse,
|
|
8
|
+
savePlan
|
|
9
|
+
} from "./chunk-FCEUJ7VK.js";
|
|
10
|
+
import {
|
|
11
|
+
createSource,
|
|
12
|
+
resolveModels,
|
|
13
|
+
runWithFallback
|
|
14
|
+
} from "./chunk-UXVSQQID.js";
|
|
15
|
+
import {
|
|
16
|
+
error,
|
|
17
|
+
kanbanEmitter,
|
|
18
|
+
log,
|
|
19
|
+
ok,
|
|
20
|
+
warn
|
|
21
|
+
} from "./chunk-5N4BWHIT.js";
|
|
22
|
+
import "./chunk-3EOEDL3T.js";
|
|
23
|
+
import "./chunk-7OCDGYDM.js";
|
|
24
|
+
import "./chunk-72CYGBT4.js";
|
|
25
|
+
import "./chunk-2TW2MJXF.js";
|
|
26
|
+
|
|
27
|
+
// src/plan/tui-bridge.ts
|
|
28
|
+
import { execSync } from "child_process";
|
|
29
|
+
import { mkdtempSync, readFileSync, writeFileSync } from "fs";
|
|
30
|
+
import { tmpdir } from "os";
|
|
31
|
+
import { join, resolve } from "path";
|
|
32
|
+
function registerPlanBridge(config) {
|
|
33
|
+
const chatHistory = [];
|
|
34
|
+
let goal = "";
|
|
35
|
+
const onUserMessage = (message) => {
|
|
36
|
+
chatHistory.push({ role: "user", content: message });
|
|
37
|
+
if (!goal) goal = message;
|
|
38
|
+
handleUserMessage(config, goal, chatHistory).catch((err) => {
|
|
39
|
+
kanbanEmitter.emit(
|
|
40
|
+
"plan:ai-message",
|
|
41
|
+
`Error: ${err instanceof Error ? err.message : String(err)}`
|
|
42
|
+
);
|
|
43
|
+
});
|
|
44
|
+
};
|
|
45
|
+
const onApproved = (issues, approvedGoal) => {
|
|
46
|
+
handleApproval(config, issues, approvedGoal).catch((err) => {
|
|
47
|
+
error(`Plan approval failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
48
|
+
});
|
|
49
|
+
};
|
|
50
|
+
const onEditIssue = (index, issue) => {
|
|
51
|
+
if (!issue) return;
|
|
52
|
+
const tmpDir = mkdtempSync(join(tmpdir(), "lisa-edit-"));
|
|
53
|
+
const tmpFile = join(tmpDir, "issue.md");
|
|
54
|
+
writeFileSync(tmpFile, issueToMarkdown(issue));
|
|
55
|
+
const editor = process.env.EDITOR || process.env.VISUAL || "vi";
|
|
56
|
+
try {
|
|
57
|
+
execSync(`${editor} "${tmpFile}"`, { stdio: "inherit" });
|
|
58
|
+
} catch {
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
const content = readFileSync(tmpFile, "utf-8");
|
|
62
|
+
const updated = markdownToIssue(content, issue);
|
|
63
|
+
kanbanEmitter.emit("plan:edit-result", index, updated);
|
|
64
|
+
};
|
|
65
|
+
kanbanEmitter.on("plan:user-message", onUserMessage);
|
|
66
|
+
kanbanEmitter.on("plan:approved", onApproved);
|
|
67
|
+
kanbanEmitter.on("plan:edit-issue", onEditIssue);
|
|
68
|
+
return () => {
|
|
69
|
+
kanbanEmitter.off("plan:user-message", onUserMessage);
|
|
70
|
+
kanbanEmitter.off("plan:approved", onApproved);
|
|
71
|
+
kanbanEmitter.off("plan:edit-issue", onEditIssue);
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
async function handleUserMessage(config, goal, chatHistory) {
|
|
75
|
+
kanbanEmitter.emit("plan:thinking");
|
|
76
|
+
const prompt = buildChatPrompt(goal, config, chatHistory);
|
|
77
|
+
const models = resolveModels(config);
|
|
78
|
+
const logDir = mkdtempSync(join(tmpdir(), "lisa-plan-"));
|
|
79
|
+
const logFile = join(logDir, "plan.log");
|
|
80
|
+
const result = await runWithFallback(models, prompt, {
|
|
81
|
+
logFile,
|
|
82
|
+
cwd: resolve(config.workspace),
|
|
83
|
+
sessionTimeout: 120
|
|
84
|
+
});
|
|
85
|
+
if (!result.success) {
|
|
86
|
+
kanbanEmitter.emit("plan:ai-message", "Failed to get AI response. Try again.");
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
try {
|
|
90
|
+
const issues = parsePlanResponse(result.output);
|
|
91
|
+
chatHistory.push({ role: "ai", content: `Decomposed into ${issues.length} issues.` });
|
|
92
|
+
kanbanEmitter.emit("plan:issues-ready", issues);
|
|
93
|
+
return;
|
|
94
|
+
} catch {
|
|
95
|
+
}
|
|
96
|
+
const response = extractChatResponse(result.output);
|
|
97
|
+
chatHistory.push({ role: "ai", content: response });
|
|
98
|
+
kanbanEmitter.emit("plan:ai-message", response);
|
|
99
|
+
}
|
|
100
|
+
async function handleApproval(config, issues, goal) {
|
|
101
|
+
const source = createSource(config.source);
|
|
102
|
+
if (!source.createIssue) {
|
|
103
|
+
error(`Source "${config.source}" does not support issue creation.`);
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
const plan = {
|
|
107
|
+
goal,
|
|
108
|
+
issues,
|
|
109
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
110
|
+
status: "approved"
|
|
111
|
+
};
|
|
112
|
+
log("Creating issues in source...");
|
|
113
|
+
const createdIds = await createPlanIssues(source, config.source_config, plan);
|
|
114
|
+
plan.status = "created";
|
|
115
|
+
plan.createdIssueIds = createdIds;
|
|
116
|
+
savePlan(resolve(config.workspace), plan);
|
|
117
|
+
ok(`${createdIds.length} issue${createdIds.length !== 1 ? "s" : ""} created via plan.`);
|
|
118
|
+
try {
|
|
119
|
+
const allIssues = await source.listIssues(config.source_config);
|
|
120
|
+
for (const issue of allIssues) {
|
|
121
|
+
kanbanEmitter.emit("issue:queued", issue);
|
|
122
|
+
}
|
|
123
|
+
} catch (err) {
|
|
124
|
+
warn(`Could not refresh kanban: ${err instanceof Error ? err.message : String(err)}`);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
function buildChatPrompt(goal, config, chatHistory) {
|
|
128
|
+
const basePrompt = buildPlanningPrompt(goal, config);
|
|
129
|
+
if (chatHistory.length <= 1) {
|
|
130
|
+
return `${basePrompt}
|
|
131
|
+
|
|
132
|
+
## Chat Mode
|
|
133
|
+
|
|
134
|
+
The user has just described their goal. You have two options:
|
|
135
|
+
|
|
136
|
+
1. **If the goal is clear and specific enough** to decompose into issues, output the JSON immediately.
|
|
137
|
+
2. **If you need clarification** (which endpoints? what technology? what scope?), respond with a SHORT question (1-2 sentences). Do NOT output JSON \u2014 just plain text.
|
|
138
|
+
|
|
139
|
+
Prefer decomposing directly when possible. Only ask if the goal is genuinely ambiguous.`;
|
|
140
|
+
}
|
|
141
|
+
const historyBlock = chatHistory.map((m) => `${m.role === "user" ? "User" : "AI"}: ${m.content}`).join("\n\n");
|
|
142
|
+
return `${basePrompt}
|
|
143
|
+
|
|
144
|
+
## Conversation History
|
|
145
|
+
|
|
146
|
+
${historyBlock}
|
|
147
|
+
|
|
148
|
+
## Instructions
|
|
149
|
+
|
|
150
|
+
Based on the conversation above, either:
|
|
151
|
+
1. **Decompose into issues** \u2014 output the JSON structure defined above.
|
|
152
|
+
2. **Ask one more question** \u2014 respond with SHORT plain text (1-2 sentences). No JSON.
|
|
153
|
+
|
|
154
|
+
If you have enough context, decompose now. Do not ask more than 3 questions total.`;
|
|
155
|
+
}
|
|
156
|
+
function extractChatResponse(output) {
|
|
157
|
+
const cleaned = output.replace(/\x1b\[[0-9;]*[A-Za-z]/g, "").trim();
|
|
158
|
+
if (cleaned.length < 500) return cleaned;
|
|
159
|
+
const lines = cleaned.split("\n").filter((l) => l.trim().length > 0);
|
|
160
|
+
return lines.slice(-10).join("\n");
|
|
161
|
+
}
|
|
162
|
+
export {
|
|
163
|
+
registerPlanBridge
|
|
164
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tarcisiopgs/lisa",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.28.0",
|
|
4
4
|
"description": "Autonomous issue resolver",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"loop",
|
|
@@ -34,7 +34,8 @@
|
|
|
34
34
|
"ink-spinner": "^5.0.0",
|
|
35
35
|
"picocolors": "^1.1.1",
|
|
36
36
|
"react": "^19.2.4",
|
|
37
|
-
"yaml": "^2.8.2"
|
|
37
|
+
"yaml": "^2.8.2",
|
|
38
|
+
"zod": "^4.3.6"
|
|
38
39
|
},
|
|
39
40
|
"devDependencies": {
|
|
40
41
|
"@biomejs/biome": "^2.4.5",
|
|
@@ -43,12 +44,12 @@
|
|
|
43
44
|
"@vitest/coverage-v8": "^4.0.18",
|
|
44
45
|
"concurrently": "^9.2.1",
|
|
45
46
|
"husky": "^9.1.7",
|
|
47
|
+
"ink-testing-library": "^4.0.0",
|
|
46
48
|
"lint-staged": "^16.3.2",
|
|
47
49
|
"tsup": "^8.5.1",
|
|
48
50
|
"tsx": "^4.21.0",
|
|
49
51
|
"typescript": "^5.9.3",
|
|
50
|
-
"vitest": "^4.0.18"
|
|
51
|
-
"ink-testing-library": "^4.0.0"
|
|
52
|
+
"vitest": "^4.0.18"
|
|
52
53
|
},
|
|
53
54
|
"engines": {
|
|
54
55
|
"node": ">=20"
|