kanbot 0.2.2__tar.gz → 0.2.3__tar.gz
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.
- {kanbot-0.2.2 → kanbot-0.2.3}/PKG-INFO +1 -1
- {kanbot-0.2.2 → kanbot-0.2.3}/kanbot/__init__.py +1 -1
- {kanbot-0.2.2 → kanbot-0.2.3}/kanbot/server/app.py +1 -1
- {kanbot-0.2.2 → kanbot-0.2.3}/kanbot/server/db.py +1 -2
- {kanbot-0.2.2 → kanbot-0.2.3}/kanbot/server/hub.py +6 -8
- {kanbot-0.2.2 → kanbot-0.2.3}/kanbot/server/static/app.js +9 -10
- {kanbot-0.2.2 → kanbot-0.2.3}/pyproject.toml +1 -1
- {kanbot-0.2.2 → kanbot-0.2.3}/scripts/e2e.py +2 -2
- {kanbot-0.2.2 → kanbot-0.2.3}/.gitignore +0 -0
- {kanbot-0.2.2 → kanbot-0.2.3}/LICENSE +0 -0
- {kanbot-0.2.2 → kanbot-0.2.3}/README.md +0 -0
- {kanbot-0.2.2 → kanbot-0.2.3}/kanbot/__main__.py +0 -0
- {kanbot-0.2.2 → kanbot-0.2.3}/kanbot/agents.py +0 -0
- {kanbot-0.2.2 → kanbot-0.2.3}/kanbot/cli.py +0 -0
- {kanbot-0.2.2 → kanbot-0.2.3}/kanbot/config.py +0 -0
- {kanbot-0.2.2 → kanbot-0.2.3}/kanbot/profiles.py +0 -0
- {kanbot-0.2.2 → kanbot-0.2.3}/kanbot/runner/__init__.py +0 -0
- {kanbot-0.2.2 → kanbot-0.2.3}/kanbot/runner/agents.py +0 -0
- {kanbot-0.2.2 → kanbot-0.2.3}/kanbot/runner/discovery.py +0 -0
- {kanbot-0.2.2 → kanbot-0.2.3}/kanbot/runner/worker.py +0 -0
- {kanbot-0.2.2 → kanbot-0.2.3}/kanbot/server/__init__.py +0 -0
- {kanbot-0.2.2 → kanbot-0.2.3}/kanbot/server/insights.py +0 -0
- {kanbot-0.2.2 → kanbot-0.2.3}/kanbot/server/schemas.py +0 -0
- {kanbot-0.2.2 → kanbot-0.2.3}/kanbot/server/static/index.html +0 -0
- {kanbot-0.2.2 → kanbot-0.2.3}/kanbot/server/static/styles.css +0 -0
- {kanbot-0.2.2 → kanbot-0.2.3}/scripts/deploy.sh +0 -0
- {kanbot-0.2.2 → kanbot-0.2.3}/scripts/e2e_live.py +0 -0
- {kanbot-0.2.2 → kanbot-0.2.3}/scripts/e2e_loop.py +0 -0
- {kanbot-0.2.2 → kanbot-0.2.3}/scripts/e2e_revive.py +0 -0
- {kanbot-0.2.2 → kanbot-0.2.3}/vercel.json +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: kanbot
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.3
|
|
4
4
|
Summary: A Kanban board where every card is a task run by your local CLI coding agents (Claude, Codex, Gemini, GLM/ZAI, or any CLI you define).
|
|
5
5
|
Project-URL: Homepage, https://github.com/publu/kanbot
|
|
6
6
|
Project-URL: Repository, https://github.com/publu/kanbot
|
|
@@ -72,7 +72,7 @@ def create_app(db_path: Optional[str] = None) -> FastAPI:
|
|
|
72
72
|
kind = col["kind"]
|
|
73
73
|
# Dropping into Running means "run it" -> queue for dispatch (unless it's
|
|
74
74
|
# already executing). Other columns just park the card.
|
|
75
|
-
mapping = {"backlog": "idle", "
|
|
75
|
+
mapping = {"backlog": "idle", "done": "done"}
|
|
76
76
|
if kind == "running":
|
|
77
77
|
if card["status"] not in ("running", "queued"):
|
|
78
78
|
db.update_card(card["id"], status="queued")
|
|
@@ -114,7 +114,6 @@ CREATE INDEX IF NOT EXISTS idx_events_session ON session_events(session_id);
|
|
|
114
114
|
DEFAULT_COLUMNS = [
|
|
115
115
|
("Backlog", "backlog"),
|
|
116
116
|
("Running", "running"),
|
|
117
|
-
("Review", "review"),
|
|
118
117
|
("Done", "done"),
|
|
119
118
|
]
|
|
120
119
|
|
|
@@ -177,7 +176,7 @@ class DB:
|
|
|
177
176
|
# Drop deprecated columns from older boards, relocating any stray cards:
|
|
178
177
|
# info -> backlog (sessions now live inline by recency)
|
|
179
178
|
# queued -> running (a card is queued via status, not a column)
|
|
180
|
-
deprecated = {"info": "backlog", "queued": "running"}
|
|
179
|
+
deprecated = {"info": "backlog", "queued": "running", "review": "done"}
|
|
181
180
|
for board in self.q("SELECT id FROM boards"):
|
|
182
181
|
bid = board["id"]
|
|
183
182
|
changed = False
|
|
@@ -208,15 +208,13 @@ class Hub:
|
|
|
208
208
|
self.db.update_session(sid, status=status, exit_code=exit_code, ended_at=now())
|
|
209
209
|
card = self.db.get_card(sess["card_id"])
|
|
210
210
|
if card:
|
|
211
|
-
|
|
211
|
+
# Any finished run (success or failure) leaves Running and lands in
|
|
212
|
+
# Done, carrying its status so the card shows ✓ done / ✗ failed.
|
|
213
|
+
new_status = "done" if status == "success" else status
|
|
212
214
|
self.db.update_card(card["id"], status=new_status)
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
col = self.db.column_by_kind(card["board_id"], target_kind)
|
|
217
|
-
if col:
|
|
218
|
-
self.db.move_card(card["id"], col["id"],
|
|
219
|
-
self.db._next_position(col["id"]))
|
|
215
|
+
col = self.db.column_by_kind(card["board_id"], "done")
|
|
216
|
+
if col:
|
|
217
|
+
self.db.move_card(card["id"], col["id"], self.db._next_position(col["id"]))
|
|
220
218
|
await self._emit_card(card["id"])
|
|
221
219
|
# Free the runner slot.
|
|
222
220
|
runner = self.runners.get(sess["runner_id"])
|
|
@@ -423,8 +423,15 @@ function renderColumns() {
|
|
|
423
423
|
// (stale sessions ARE the backlog). No dedicated column.
|
|
424
424
|
const RECENT_DONE_S = 30 * 60;
|
|
425
425
|
const nowS = Date.now() / 1000;
|
|
426
|
+
// Dedupe: a session adopted as a card (resumed) is represented by that card,
|
|
427
|
+
// so hide its discovered twin. Also hide an active session whose cwd matches a
|
|
428
|
+
// currently-running task card (that's the card's own session writing to disk).
|
|
429
|
+
const adopted = new Set(S.cards.filter(c => c.resume_of).map(c => c.resume_of));
|
|
430
|
+
const runningCwds = new Set(S.cards.filter(c => c.status === 'running' && c.cwd).map(c => c.cwd));
|
|
426
431
|
const byBucket = { backlog: [], running: [], done: [] };
|
|
427
432
|
for (const s of S.agentSessions) {
|
|
433
|
+
if (adopted.has(s.session_id)) continue;
|
|
434
|
+
if (s.active && runningCwds.has(s.cwd)) continue;
|
|
428
435
|
if (s.active) byBucket.running.push(s);
|
|
429
436
|
else if ((nowS - (s.mtime || 0)) <= RECENT_DONE_S) byBucket.done.push(s);
|
|
430
437
|
else byBucket.backlog.push(s);
|
|
@@ -780,14 +787,6 @@ function renderDrawerBody(card) {
|
|
|
780
787
|
(max, until) => patchCard(card.id, { loop_max: max, loop_until: until }));
|
|
781
788
|
body.appendChild(loop.wrap);
|
|
782
789
|
|
|
783
|
-
// auto-advance toggle
|
|
784
|
-
const tg = el('label', 'toggle');
|
|
785
|
-
const cb = el('input'); cb.type = 'checkbox'; cb.checked = !!card.auto_advance;
|
|
786
|
-
cb.onchange = () => patchCard(card.id, { auto_advance: cb.checked });
|
|
787
|
-
tg.appendChild(cb); tg.appendChild(el('span', 'track'));
|
|
788
|
-
tg.appendChild(el('span', null, 'Auto-advance to Review on success'));
|
|
789
|
-
body.appendChild(tg);
|
|
790
|
-
|
|
791
790
|
// tags
|
|
792
791
|
body.appendChild(renderTagsField(card));
|
|
793
792
|
|
|
@@ -1084,10 +1083,10 @@ CONTENT TYPE
|
|
|
1084
1083
|
CORE MODEL
|
|
1085
1084
|
Board { id, name, repo_path, created_at }
|
|
1086
1085
|
Column { id, board_id, name, kind, position }
|
|
1087
|
-
kind in: backlog | running |
|
|
1086
|
+
kind in: backlog | running | done (queue is a status, not a column)
|
|
1088
1087
|
Card { id, board_id, column_id, title, prompt, agent, cwd, status,
|
|
1089
1088
|
position, auto_advance, resume_of, pin_runner, tags[], created_at, updated_at }
|
|
1090
|
-
status in: idle | queued | running |
|
|
1089
|
+
status in: idle | queued | running | done | failed | cancelled
|
|
1091
1090
|
agent: "auto" or an agent name (claude, codex, gemini, glm, shell, ...)
|
|
1092
1091
|
resume_of: an external session id this card resumes (optional)
|
|
1093
1092
|
pin_runner: restrict execution to one runner id (optional)
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "kanbot"
|
|
7
|
-
version = "0.2.
|
|
7
|
+
version = "0.2.3"
|
|
8
8
|
description = "A Kanban board where every card is a task run by your local CLI coding agents (Claude, Codex, Gemini, GLM/ZAI, or any CLI you define)."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.9"
|
|
@@ -74,9 +74,9 @@ def main():
|
|
|
74
74
|
|
|
75
75
|
card_after = next(x for x in c.get(f"/api/boards/{bid}").json()["cards"] if x["id"] == card["id"])
|
|
76
76
|
print("card status after run:", card_after["status"])
|
|
77
|
-
assert card_after["status"] == "
|
|
77
|
+
assert card_after["status"] == "done", f"expected done, got {card_after['status']}"
|
|
78
78
|
|
|
79
|
-
print("\n✅ E2E PASSED: task queued, executed by runner, streamed logs,
|
|
79
|
+
print("\n✅ E2E PASSED: task queued, executed by runner, streamed logs, landed in Done.")
|
|
80
80
|
|
|
81
81
|
|
|
82
82
|
if __name__ == "__main__":
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|