create-claude-kanban 2.0.0 → 2.0.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/package.json +1 -1
- package/templates/kanban.cjs +108 -6
- package/templates/kanban.html +12 -11
package/package.json
CHANGED
package/templates/kanban.cjs
CHANGED
|
@@ -12,7 +12,6 @@ delete process.env.CLAUDECODE;
|
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
14
|
var config;
|
|
15
|
-
// 1) kanban.config.json 로드 시도
|
|
16
15
|
var _configPath = require("path").join(__dirname, "..", "kanban.config.json");
|
|
17
16
|
try {
|
|
18
17
|
if (require("fs").existsSync(_configPath)) {
|
|
@@ -32,7 +31,6 @@ try {
|
|
|
32
31
|
};
|
|
33
32
|
} else { throw new Error("no config"); }
|
|
34
33
|
} catch {
|
|
35
|
-
// 2) fallback: env vars
|
|
36
34
|
try { require("dotenv").config({ path: require("path").join(__dirname, "..", ".env") }); } catch {}
|
|
37
35
|
config = {
|
|
38
36
|
port: parseInt(process.env.PORT) || 4040,
|
|
@@ -577,7 +575,7 @@ function getNextId() {
|
|
|
577
575
|
function createTask(data) {
|
|
578
576
|
const id = getNextId();
|
|
579
577
|
const now = new Date().toISOString();
|
|
580
|
-
var projectId = data.project || readProjects()[0].id || "
|
|
578
|
+
var projectId = data.project || readProjects()[0].id || "default";
|
|
581
579
|
var projectDir = getProjectDir(projectId);
|
|
582
580
|
if (!fs.existsSync(projectDir)) fs.mkdirSync(projectDir, { recursive: true });
|
|
583
581
|
const task = {
|
|
@@ -1764,7 +1762,8 @@ const server = http.createServer(async (req, res) => {
|
|
|
1764
1762
|
var chatBody = await parseBody(req);
|
|
1765
1763
|
var chatMessage = chatBody.message || "";
|
|
1766
1764
|
var chatModel = chatBody.model || "sonnet";
|
|
1767
|
-
var chatProject = chatBody.project || readProjects()[0].id || "
|
|
1765
|
+
var chatProject = chatBody.project || readProjects()[0].id || "default";
|
|
1766
|
+
var chatHistory = chatBody.history || []; // [{role,content}, ...]
|
|
1768
1767
|
|
|
1769
1768
|
var tasks = readAllTasks(chatProject);
|
|
1770
1769
|
var projInfo = readProjects().find(function(p) { return p.id === chatProject; });
|
|
@@ -1783,10 +1782,19 @@ const server = http.createServer(async (req, res) => {
|
|
|
1783
1782
|
chatSessionModel = chatModel;
|
|
1784
1783
|
}
|
|
1785
1784
|
|
|
1786
|
-
// Build
|
|
1785
|
+
// Build conversation history string for new sessions
|
|
1786
|
+
function buildHistoryContext(hist) {
|
|
1787
|
+
if (!hist || hist.length === 0) return "";
|
|
1788
|
+
return "\n\n## 이전 대화 기록\n" + hist.map(function(m) {
|
|
1789
|
+
var label = m.role === "user" ? "[User]" : "[Assistant]";
|
|
1790
|
+
return label + ": " + m.content;
|
|
1791
|
+
}).join("\n\n") + "\n\n---\n";
|
|
1792
|
+
}
|
|
1793
|
+
|
|
1794
|
+
// Build input — include system context + history only for new sessions
|
|
1787
1795
|
var chatInput = "";
|
|
1788
1796
|
if (!chatSessionId) {
|
|
1789
|
-
chatInput = chatPrompt + "\n\n[User]: " + chatMessage;
|
|
1797
|
+
chatInput = chatPrompt + buildHistoryContext(chatHistory) + "\n\n[User]: " + chatMessage;
|
|
1790
1798
|
} else {
|
|
1791
1799
|
chatInput = chatMessage;
|
|
1792
1800
|
}
|
|
@@ -1877,6 +1885,100 @@ const server = http.createServer(async (req, res) => {
|
|
|
1877
1885
|
|
|
1878
1886
|
chatProc.on("close", function (code) {
|
|
1879
1887
|
try {
|
|
1888
|
+
// Detect stale session error → auto-retry without --resume
|
|
1889
|
+
if (code !== 0 && rawOut.includes("No conversation found with session ID")) {
|
|
1890
|
+
chatSessionId = null;
|
|
1891
|
+
chatSessionModel = null;
|
|
1892
|
+
res.write("data: " + JSON.stringify({ type: "chat", chunk: "(세션 만료 — 새 세션으로 재시도 중...)\n\n" }) + "\n\n");
|
|
1893
|
+
|
|
1894
|
+
// Retry without --resume
|
|
1895
|
+
var retryArgs = ["-p", "--verbose", "--output-format", "stream-json",
|
|
1896
|
+
"--model", chatModel, "--dangerously-skip-permissions", "--no-session-persistence"];
|
|
1897
|
+
var retryInput = chatPrompt + buildHistoryContext(chatHistory) + "\n\n[User]: " + chatMessage;
|
|
1898
|
+
var retryProc = spawn("claude", retryArgs, {
|
|
1899
|
+
cwd: path.join(__dirname, ".."),
|
|
1900
|
+
env: chatEnv,
|
|
1901
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
1902
|
+
});
|
|
1903
|
+
retryProc.stdin.write(retryInput);
|
|
1904
|
+
retryProc.stdin.end();
|
|
1905
|
+
|
|
1906
|
+
var retryBuf = "", retryRaw = "", retryFull = "";
|
|
1907
|
+
|
|
1908
|
+
retryProc.stdout.on("data", function (data) {
|
|
1909
|
+
var chunk = data.toString();
|
|
1910
|
+
retryRaw += chunk;
|
|
1911
|
+
retryBuf += chunk;
|
|
1912
|
+
var lines = retryBuf.split("\n");
|
|
1913
|
+
retryBuf = lines.pop();
|
|
1914
|
+
for (var li = 0; li < lines.length; li++) {
|
|
1915
|
+
var ln = lines[li];
|
|
1916
|
+
if (!ln.trim()) continue;
|
|
1917
|
+
try {
|
|
1918
|
+
var json = JSON.parse(ln);
|
|
1919
|
+
if (json.type === "system" && json.session_id) {
|
|
1920
|
+
chatSessionId = json.session_id;
|
|
1921
|
+
chatSessionModel = chatModel;
|
|
1922
|
+
res.write("data: " + JSON.stringify({ type: "chat_session", sessionId: chatSessionId }) + "\n\n");
|
|
1923
|
+
}
|
|
1924
|
+
var text = "";
|
|
1925
|
+
if (json.type === "assistant" && json.subtype === "text") text = json.text || "";
|
|
1926
|
+
else if (json.type === "assistant" && json.message && json.message.content) {
|
|
1927
|
+
json.message.content.forEach(function (c) { if (c.type === "text") text += c.text; });
|
|
1928
|
+
} else if (json.type === "content_block_delta" && json.delta && json.delta.text) text = json.delta.text;
|
|
1929
|
+
if (text) { retryFull += text; res.write("data: " + JSON.stringify({ type: "chat", chunk: text }) + "\n\n"); }
|
|
1930
|
+
if (json.type === "assistant" && json.subtype === "tool_use") {
|
|
1931
|
+
var tn = json.tool || json.name || "Tool";
|
|
1932
|
+
var ti = "";
|
|
1933
|
+
if (json.input) {
|
|
1934
|
+
if (typeof json.input === "string") ti = json.input;
|
|
1935
|
+
else if (json.input.command) ti = json.input.command;
|
|
1936
|
+
else if (json.input.file_path) ti = json.input.file_path;
|
|
1937
|
+
else ti = JSON.stringify(json.input).slice(0, 200);
|
|
1938
|
+
}
|
|
1939
|
+
res.write("data: " + JSON.stringify({ type: "chat_tool_use", tool: tn, input: ti }) + "\n\n");
|
|
1940
|
+
}
|
|
1941
|
+
if (json.type === "tool_result" || (json.type === "tool" && json.subtype === "result")) {
|
|
1942
|
+
var ro = json.output || json.text || json.content || "";
|
|
1943
|
+
if (typeof ro !== "string") ro = JSON.stringify(ro).slice(0, 2000);
|
|
1944
|
+
res.write("data: " + JSON.stringify({ type: "chat_tool_result", output: String(ro).slice(0, 2000) }) + "\n\n");
|
|
1945
|
+
}
|
|
1946
|
+
} catch (e) {}
|
|
1947
|
+
}
|
|
1948
|
+
});
|
|
1949
|
+
|
|
1950
|
+
retryProc.on("close", function (rc) {
|
|
1951
|
+
try {
|
|
1952
|
+
if (!retryRaw.trim() || rc !== 0) {
|
|
1953
|
+
res.write("data: " + JSON.stringify({ type: "chat_debug", rawOut: retryRaw.slice(0, 2000), exitCode: rc }) + "\n\n");
|
|
1954
|
+
}
|
|
1955
|
+
var parsed = parseActionBlocks(retryFull);
|
|
1956
|
+
if (parsed.actions.length > 0) {
|
|
1957
|
+
var actionResults = [];
|
|
1958
|
+
for (var ai = 0; ai < parsed.actions.length; ai++) {
|
|
1959
|
+
if (parsed.actions[ai].type === "task_create" && parsed.actions[ai].data) {
|
|
1960
|
+
parsed.actions[ai].data.project = parsed.actions[ai].data.project || chatProject;
|
|
1961
|
+
}
|
|
1962
|
+
var results = executeAction(parsed.actions[ai]);
|
|
1963
|
+
actionResults = actionResults.concat(results);
|
|
1964
|
+
}
|
|
1965
|
+
res.write("data: " + JSON.stringify({ type: "chat_actions", results: actionResults }) + "\n\n");
|
|
1966
|
+
}
|
|
1967
|
+
res.write("data: " + JSON.stringify({ type: "chat_done" }) + "\n\n");
|
|
1968
|
+
res.end();
|
|
1969
|
+
if (parsed.cleaned || retryFull) {
|
|
1970
|
+
appendOrchestratorHistory("orchestrator", (parsed.cleaned || retryFull));
|
|
1971
|
+
extractAndSaveLearnings(retryFull);
|
|
1972
|
+
}
|
|
1973
|
+
} catch (e) {}
|
|
1974
|
+
});
|
|
1975
|
+
|
|
1976
|
+
req.on("close", function () {
|
|
1977
|
+
try { retryProc.kill(); } catch (e) {}
|
|
1978
|
+
});
|
|
1979
|
+
return;
|
|
1980
|
+
}
|
|
1981
|
+
|
|
1880
1982
|
// Debug info if no output
|
|
1881
1983
|
if (!rawOut.trim() || code !== 0) {
|
|
1882
1984
|
res.write("data: " + JSON.stringify({ type: "chat_debug", rawOut: rawOut.slice(0, 2000), stderr: chatErr.slice(0, 2000), exitCode: code }) + "\n\n");
|
package/templates/kanban.html
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
<head>
|
|
4
4
|
<meta charset="UTF-8">
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
-
<title>
|
|
6
|
+
<title>Agent Kanban</title>
|
|
7
7
|
<link href="https://cdn.jsdelivr.net/gh/orioncactus/pretendard@v1.3.9/dist/web/variable/pretendardvariable-dynamic-subset.min.css" rel="stylesheet">
|
|
8
8
|
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600&display=swap" rel="stylesheet">
|
|
9
9
|
<style>
|
|
@@ -1341,7 +1341,7 @@
|
|
|
1341
1341
|
|
|
1342
1342
|
<div class="header">
|
|
1343
1343
|
<div class="header-left">
|
|
1344
|
-
<div class="logo">
|
|
1344
|
+
<div class="logo">Agent<span class="logo-dot">.</span>Kanban</div>
|
|
1345
1345
|
<div class="header-sub" id="taskSource">~/.claude/tasks/</div>
|
|
1346
1346
|
</div>
|
|
1347
1347
|
<div class="stats">
|
|
@@ -2221,9 +2221,9 @@ function openChat(){
|
|
|
2221
2221
|
var panel=document.getElementById("chatPanel");
|
|
2222
2222
|
panel.classList.add("open");
|
|
2223
2223
|
// restore saved size
|
|
2224
|
-
var savedH=localStorage.getItem("
|
|
2225
|
-
var savedW=localStorage.getItem("
|
|
2226
|
-
var savedExp=localStorage.getItem("
|
|
2224
|
+
var savedH=localStorage.getItem("kanban_chat_height");
|
|
2225
|
+
var savedW=localStorage.getItem("kanban_chat_width");
|
|
2226
|
+
var savedExp=localStorage.getItem("kanban_chat_expanded")==="1";
|
|
2227
2227
|
if(savedExp){chatExpanded=true;panel.classList.add("expanded");}
|
|
2228
2228
|
else{
|
|
2229
2229
|
if(savedH)panel.style.height=savedH;
|
|
@@ -2264,11 +2264,11 @@ function loadChatHistory(){
|
|
|
2264
2264
|
}
|
|
2265
2265
|
chatLoaded=true;
|
|
2266
2266
|
}).catch(function(){chatLoaded=true;});
|
|
2267
|
-
var savedModel=localStorage.getItem("
|
|
2267
|
+
var savedModel=localStorage.getItem("kanban_chat_model");
|
|
2268
2268
|
if(savedModel){var sel=document.getElementById("chatModel");if(sel)sel.value=savedModel;}
|
|
2269
2269
|
}
|
|
2270
2270
|
function onChatModelChange(el){
|
|
2271
|
-
localStorage.setItem("
|
|
2271
|
+
localStorage.setItem("kanban_chat_model",el.value);
|
|
2272
2272
|
fetch("/api/chat/session",{method:"DELETE"}).catch(function(){});
|
|
2273
2273
|
var badge=document.getElementById("chatSessionBadge");
|
|
2274
2274
|
if(badge)badge.style.display="none";
|
|
@@ -2285,7 +2285,7 @@ function toggleChatExpand(){
|
|
|
2285
2285
|
chatExpanded=!chatExpanded;
|
|
2286
2286
|
panel.classList.toggle("expanded",chatExpanded);
|
|
2287
2287
|
if(chatExpanded){panel.style.height="";panel.style.width="";}
|
|
2288
|
-
localStorage.setItem("
|
|
2288
|
+
localStorage.setItem("kanban_chat_expanded",chatExpanded?"1":"0");
|
|
2289
2289
|
}
|
|
2290
2290
|
(function(){
|
|
2291
2291
|
var panel=document.getElementById("chatPanel");
|
|
@@ -2305,7 +2305,7 @@ function toggleChatExpand(){
|
|
|
2305
2305
|
function onUp(){
|
|
2306
2306
|
hHandle.classList.remove("active");
|
|
2307
2307
|
panel.style.transition="";
|
|
2308
|
-
localStorage.setItem("
|
|
2308
|
+
localStorage.setItem("kanban_chat_height",panel.style.height);
|
|
2309
2309
|
document.removeEventListener("mousemove",onMove);
|
|
2310
2310
|
document.removeEventListener("mouseup",onUp);
|
|
2311
2311
|
}
|
|
@@ -2328,7 +2328,7 @@ function toggleChatExpand(){
|
|
|
2328
2328
|
function onUp(){
|
|
2329
2329
|
wHandle.classList.remove("active");
|
|
2330
2330
|
panel.style.transition="";
|
|
2331
|
-
localStorage.setItem("
|
|
2331
|
+
localStorage.setItem("kanban_chat_width",panel.style.width);
|
|
2332
2332
|
document.removeEventListener("mousemove",onMove);
|
|
2333
2333
|
document.removeEventListener("mouseup",onUp);
|
|
2334
2334
|
}
|
|
@@ -2441,7 +2441,8 @@ async function sendChat(){
|
|
|
2441
2441
|
var response=await fetch("/api/chat",{
|
|
2442
2442
|
method:"POST",
|
|
2443
2443
|
headers:{"Content-Type":"application/json"},
|
|
2444
|
-
body:JSON.stringify({message:message,model:model,project:currentProject})
|
|
2444
|
+
body:JSON.stringify({message:message,model:model,project:currentProject,history:chatMessages.slice(0,-2).slice(-20).filter(function(m){return m.role&&m.content;}).map(function(m){return{role:m.role,content:m.content.slice(0,500)};})})
|
|
2445
|
+
|
|
2445
2446
|
});
|
|
2446
2447
|
if(!response.ok){
|
|
2447
2448
|
var err=await response.json().catch(function(){return{error:"Request failed"};});
|