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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-claude-kanban",
3
- "version": "2.0.0",
3
+ "version": "2.0.1",
4
4
  "description": "Scaffold a multi-agent kanban system for Claude Code projects",
5
5
  "type": "module",
6
6
  "bin": {
@@ -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 || "apex";
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 || "apex";
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 input include system context only for new sessions
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");
@@ -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>APEX Agent Kanban</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">APEX<span class="logo-dot">.</span>Kanban</div>
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("apex_chat_height");
2225
- var savedW=localStorage.getItem("apex_chat_width");
2226
- var savedExp=localStorage.getItem("apex_chat_expanded")==="1";
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("apex_chat_model");
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("apex_chat_model",el.value);
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("apex_chat_expanded",chatExpanded?"1":"0");
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("apex_chat_height",panel.style.height);
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("apex_chat_width",panel.style.width);
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"};});