@mgeri1993/claude-task-manager 1.0.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/.env.example +2 -0
- package/Dockerfile +11 -0
- package/LICENSE +21 -0
- package/README.hu.md +255 -0
- package/README.md +253 -0
- package/api/index.php +173 -0
- package/bin/add-agent.sh +77 -0
- package/bin/ctm +160 -0
- package/docker-compose.yml +14 -0
- package/engine/check-update.sh +48 -0
- package/engine/projects.sh +164 -0
- package/engine/task.sh +926 -0
- package/favicon.ico +6 -0
- package/favicon.svg +6 -0
- package/index.html +141 -0
- package/install.sh +231 -0
- package/js/ApiClient.js +63 -0
- package/js/App.js +547 -0
- package/js/BoardView.js +205 -0
- package/js/ContextPanel.js +47 -0
- package/js/ContextStore.js +39 -0
- package/js/ProjectStore.js +27 -0
- package/js/TaskModal.js +112 -0
- package/js/TaskStore.js +73 -0
- package/js/UrlState.js +53 -0
- package/js/Utils.js +202 -0
- package/js/i18n.js +338 -0
- package/js/main.js +3 -0
- package/package.json +85 -0
- package/style.css +396 -0
- package/templates/SKILL.md.tmpl +175 -0
- package/templates/agents/ctm-backend-developer.md.tmpl +53 -0
- package/templates/agents/ctm-code-investigator.md.tmpl +49 -0
- package/templates/agents/ctm-frontend-developer.md.tmpl +53 -0
- package/templates/hooks/allow-task-sh.sh.tmpl +59 -0
- package/templates/hooks/notify-inbox.sh.tmpl +53 -0
- package/templates/tm-custom.md.tmpl +54 -0
package/style.css
ADDED
|
@@ -0,0 +1,396 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Task Manager – Kanban board stílusai (dark redesign).
|
|
3
|
+
Megjegyzés: a Tailwind Play CDN (board.html <head>) csak a DOM-ban lévő
|
|
4
|
+
utility-osztályokat oldja fel, EBBEN a külső fájlban nem — ezért itt minden
|
|
5
|
+
komponens-stílus sima CSS, a lenti CSS custom property-kre (design tokenek)
|
|
6
|
+
építve. A JS a --todo/--in_progress/... tokeneket inline
|
|
7
|
+
style="background:var(--todo)" formában használja (ld. js/BoardView.js,
|
|
8
|
+
js/TaskModal.js) — ez a mechanizmus változatlan.
|
|
9
|
+
|
|
10
|
+
A paletta a Figma-ből exportált „Redesign a dark mode" mockup tükre:
|
|
11
|
+
mély szénszürke háttér (#0f1115), lebegő panelek, finom fehér-alfa keretek,
|
|
12
|
+
Geist / Geist Mono tipográfia, telítettebb státusz-akcentek.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
/* Beégetett (hardcoded) DARK téma – az OS beállításától függetlenül mindig sötét. */
|
|
16
|
+
:root {
|
|
17
|
+
--bg: #0f1115; /* app-háttér */
|
|
18
|
+
--panel: #14171d; /* oszlop / sáv / lane háttér */
|
|
19
|
+
--panel-2: #181b22; /* input, select, chip, tag, jegyzet-kártya */
|
|
20
|
+
--panel-3: #232a33; /* gomb, count-pill, süllyesztett felszín */
|
|
21
|
+
--card: #1b1f27; /* kártya háttér */
|
|
22
|
+
--card-hover: #20242e; /* kártya hover háttér */
|
|
23
|
+
--track: rgba(255,255,255,.06);/* progress / bar sáv-háttér */
|
|
24
|
+
|
|
25
|
+
--text: #e6e8ec; /* fő szöveg */
|
|
26
|
+
--text-strong: #f0f2f4; /* cím, kiemelt szám */
|
|
27
|
+
--muted: #9aa0aa; /* másodlagos szöveg */
|
|
28
|
+
--muted-2: #656b76; /* halvány felirat / ikon */
|
|
29
|
+
|
|
30
|
+
--border: rgba(255,255,255,.07);
|
|
31
|
+
--border-soft: rgba(255,255,255,.05);
|
|
32
|
+
--border-strong: rgba(255,255,255,.13);
|
|
33
|
+
|
|
34
|
+
--shadow: 0 1px 2px rgba(0,0,0,.4);
|
|
35
|
+
--shadow-lg: 0 8px 22px -10px rgba(0,0,0,.6);
|
|
36
|
+
--shadow-modal: 0 24px 60px -16px rgba(0,0,0,.7);
|
|
37
|
+
|
|
38
|
+
/* Státusz-akcentek (a mockup STATUS palettája). A JS var(--...) formában hivatkozik rájuk. */
|
|
39
|
+
--todo: #8b93a1; --in_progress: #4f8ff7; --blocked: #f2635e;
|
|
40
|
+
--review: #b57cf6; --done: #46c07f;
|
|
41
|
+
|
|
42
|
+
/* --ok/--err: a .dot állapotjelzőn (WCAG 1.4.11 ≥3:1 sötét panelen) */
|
|
43
|
+
--ok: #46c07f; --err: #f2635e; --accent: #5b8def;
|
|
44
|
+
|
|
45
|
+
/* Kontraszt-célú kiegészítő tokenek (WCAG AA), dark értékekkel */
|
|
46
|
+
--accent-solid: #3f6fd6; /* tömör accent-háttér + fehér szöveg (gomb.on, badge.team, ctx-badge) */
|
|
47
|
+
--pill-fg-light: #ffffff; /* pill szöveg todo/in_progress/blocked hátteren */
|
|
48
|
+
--pill-fg-dark: #12151b; /* pill szöveg review/done (világosabb) hátteren */
|
|
49
|
+
--danger-text: #e8837f; /* dep-badge / note / banner szöveg */
|
|
50
|
+
--danger-bg: rgba(242,99,94,.11); /* dep-badge / note / banner háttér */
|
|
51
|
+
--danger-border: rgba(242,99,94,.26);
|
|
52
|
+
--accent-tint-text: #9fc0ff; /* .badge.ch szöveg */
|
|
53
|
+
--accent-tint-bg: rgba(91,141,239,.14); /* .badge.ch háttér */
|
|
54
|
+
|
|
55
|
+
/* Egységes lekerekítés-skála a kártya/gomb/panel-szintű elemekhez. */
|
|
56
|
+
--radius-sm: 6px; --radius-md: 9px; --radius-lg: 13px; --radius-full: 999px;
|
|
57
|
+
|
|
58
|
+
--font: "Geist", system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
|
|
59
|
+
--mono: "Geist Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
|
60
|
+
}
|
|
61
|
+
* { box-sizing: border-box; }
|
|
62
|
+
html, body { height: 100%; }
|
|
63
|
+
body {
|
|
64
|
+
margin: 0; font: 400 13.5px/1.5 var(--font);
|
|
65
|
+
background: var(--bg); color: var(--text);
|
|
66
|
+
display: flex; flex-direction: column; height: 100vh; overflow: hidden;
|
|
67
|
+
position: relative; -webkit-font-smoothing: antialiased; text-rendering: optimizeLegibility;
|
|
68
|
+
}
|
|
69
|
+
/* Halvány kék fény a viewport tetején (a mockup radial-gradient glow-ja). */
|
|
70
|
+
body::before {
|
|
71
|
+
content: ""; position: fixed; left: 0; right: 0; top: 0; height: 340px;
|
|
72
|
+
background: radial-gradient(120% 130% at 28% 0, rgba(91,141,239,.07), transparent 62%);
|
|
73
|
+
pointer-events: none; z-index: 0;
|
|
74
|
+
}
|
|
75
|
+
body > * { position: relative; z-index: 1; }
|
|
76
|
+
|
|
77
|
+
/* Visszafogott, a sötét témához illő scrollbar (webkit + Firefox). */
|
|
78
|
+
* { scrollbar-width: thin; scrollbar-color: rgba(255,255,255,.12) transparent; }
|
|
79
|
+
*::-webkit-scrollbar { width: 10px; height: 10px; }
|
|
80
|
+
*::-webkit-scrollbar-track { background: transparent; }
|
|
81
|
+
*::-webkit-scrollbar-thumb { background: rgba(255,255,255,.09); border-radius: var(--radius-full); border: 2px solid transparent; background-clip: padding-box; }
|
|
82
|
+
*::-webkit-scrollbar-thumb:hover { background: rgba(255,255,255,.16); background-clip: padding-box; }
|
|
83
|
+
|
|
84
|
+
/* A fejléc és a sávok fix magasak; csak a board görög. */
|
|
85
|
+
header, .stats, .controls, .agents-wrap, .banner { flex: 0 0 auto; }
|
|
86
|
+
/* 3-zónás fejléc-elrendezés (a mockup mintája): márka+élő-jelző balra, kereső+forrás
|
|
87
|
+
középen, a poll/kontextus/szünet/frissítés-vezérlők jobbra. */
|
|
88
|
+
header {
|
|
89
|
+
display: flex; flex-wrap: wrap; align-items: center; gap: 10px 14px; padding: 13px 20px;
|
|
90
|
+
background: rgba(15,17,21,.82); backdrop-filter: blur(10px);
|
|
91
|
+
border-bottom: 1px solid var(--border-soft); position: sticky; top: 0; z-index: 20;
|
|
92
|
+
}
|
|
93
|
+
.hd-left { display: flex; align-items: center; gap: 12px; flex: none; }
|
|
94
|
+
.hd-center { flex: 1 1 auto; display: flex; align-items: center; justify-content: center; gap: 10px; min-width: 0; flex-wrap: wrap; }
|
|
95
|
+
.hd-right { display: flex; align-items: center; gap: 8px; flex: none; }
|
|
96
|
+
header h1 { display: inline-flex; align-items: center; gap: 10px; font-size: 15.5px; margin: 0; font-weight: 600; letter-spacing: -.01em; color: var(--text-strong); white-space: nowrap; }
|
|
97
|
+
/* Equalizer-logó a fejlécben (a mockup jelölése). */
|
|
98
|
+
.logo { display: inline-flex; align-items: flex-end; justify-content: center; gap: 2px; width: 31px; height: 31px; border-radius: 9px; background: rgba(91,141,239,.13); border: 1px solid rgba(91,141,239,.32); flex: none; }
|
|
99
|
+
.logo i { width: 3px; border-radius: 1px; background: var(--accent); }
|
|
100
|
+
.logo i:nth-child(1) { height: 8px; }
|
|
101
|
+
.logo i:nth-child(2) { height: 14px; }
|
|
102
|
+
.logo i:nth-child(3) { height: 6px; }
|
|
103
|
+
/* Fejléc élő órája a státusz-pillben. */
|
|
104
|
+
.clock { font: 500 12px var(--mono); color: var(--muted-2); }
|
|
105
|
+
label.ctl { color: var(--muted-2); font-size: 11px; font-weight: 500; display: inline-flex; align-items: center; gap: 7px; }
|
|
106
|
+
/* Inline SVG-ikonok igazítása + színe a különböző kontextusokban. */
|
|
107
|
+
.ico { flex: none; display: inline-block; vertical-align: middle; }
|
|
108
|
+
.ico-accent { color: var(--accent); }
|
|
109
|
+
label.ctl .ico { color: var(--muted-2); }
|
|
110
|
+
.stat .ico, .ro .ico { color: var(--muted-2); }
|
|
111
|
+
.tag .ico { color: currentColor; }
|
|
112
|
+
.fi-top .ico { color: var(--muted-2); flex: none; }
|
|
113
|
+
.lane-head .ico { color: var(--muted); flex: none; }
|
|
114
|
+
.status svg { flex: none; }
|
|
115
|
+
|
|
116
|
+
/* Beviteli mezők: süllyesztett, sötét kitöltés. */
|
|
117
|
+
input, select {
|
|
118
|
+
font: 500 12.5px var(--font); padding: 0 14px; border-radius: var(--radius-md);
|
|
119
|
+
border: 1px solid var(--border); background: var(--panel-2); color: var(--text); color-scheme: dark;
|
|
120
|
+
height: 36px;
|
|
121
|
+
}
|
|
122
|
+
input::placeholder { color: var(--muted-2); }
|
|
123
|
+
input:focus-visible, select:focus-visible { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 26%, transparent); }
|
|
124
|
+
select {
|
|
125
|
+
padding: 0 32px 0 13px; cursor: pointer; font-family: var(--mono); font-size: 12px;
|
|
126
|
+
appearance: none; -webkit-appearance: none; -moz-appearance: none;
|
|
127
|
+
background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%239aa0aa' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'><path d='M6 9l6 6 6-6'/></svg>");
|
|
128
|
+
background-repeat: no-repeat; background-position: right 11px center; background-size: 13px;
|
|
129
|
+
}
|
|
130
|
+
input#src { width: 100%; font-family: var(--mono); font-size: 12px; }
|
|
131
|
+
|
|
132
|
+
/* Kereső: ikon + input egy közös, süllyesztett dobozban (a mockup search-boxa). */
|
|
133
|
+
.search-box { display: inline-flex; align-items: center; gap: 9px; flex: 0 1 260px; min-width: 150px; padding: 0 12px; height: 36px; border-radius: var(--radius-md); background: var(--panel-2); border: 1px solid var(--border); color: var(--muted-2); }
|
|
134
|
+
.search-box input#q { flex: 1; min-width: 0; height: auto; border: none; background: transparent; padding: 0; color: var(--text); }
|
|
135
|
+
.search-box input#q:focus-visible { outline: none; box-shadow: none; }
|
|
136
|
+
|
|
137
|
+
/* Forrás: egyetlen natív select a projektek közti váltáshoz (nincs külön gomb/popover). */
|
|
138
|
+
.src-box { display: inline-flex; align-items: center; gap: 8px; flex: 1 1 260px; min-width: 160px; max-width: 360px; padding: 0 11px; height: 36px; border-radius: var(--radius-sm); background: var(--panel); border: 1px solid var(--border-soft); }
|
|
139
|
+
.src-box .lbl { color: var(--muted-2); font: 500 11px var(--font); flex: none; }
|
|
140
|
+
.src-box .src-dot { width: 6px; height: 6px; border-radius: 50%; background: var(--accent); flex: none; }
|
|
141
|
+
.src-select { flex: 1; min-width: 0; height: 26px; border: none; background: transparent; padding: 0; }
|
|
142
|
+
.src-select:focus-visible { outline: none; box-shadow: none; }
|
|
143
|
+
|
|
144
|
+
/* --- Projektek modal (wrapper-lista + másolás) --- */
|
|
145
|
+
.proj-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 11px 0; border-bottom: 1px solid var(--border-soft); }
|
|
146
|
+
.proj-row:last-child { border-bottom: none; }
|
|
147
|
+
.proj-row-label { font: 600 13px var(--font); color: var(--text); }
|
|
148
|
+
.proj-row-id { font: 500 11px var(--mono); margin-top: 3px; }
|
|
149
|
+
button.copied { background: var(--accent-solid); color: #fff; border-color: transparent; }
|
|
150
|
+
|
|
151
|
+
/* --- Egységes gomb-rendszer --- */
|
|
152
|
+
button {
|
|
153
|
+
display: inline-flex; align-items: center; justify-content: center; gap: 7px;
|
|
154
|
+
font: 500 12px var(--font); line-height: 1; height: 36px;
|
|
155
|
+
padding: 0 15px; border-radius: var(--radius-md);
|
|
156
|
+
border: 1px solid var(--border); background: var(--panel); color: var(--text); cursor: pointer;
|
|
157
|
+
white-space: nowrap;
|
|
158
|
+
transition: background .12s ease, border-color .12s ease, color .12s ease, filter .12s ease, transform .04s ease;
|
|
159
|
+
}
|
|
160
|
+
button:hover { background: #1b1f27; border-color: var(--border-strong); color: var(--text-strong); }
|
|
161
|
+
button:active { transform: translateY(1px); }
|
|
162
|
+
button:focus-visible { outline: none; box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 40%, transparent); }
|
|
163
|
+
button.on { background: var(--accent-solid); color: #fff; border-color: transparent; box-shadow: 0 1px 2px rgba(0,0,0,.35); font-weight: 600; }
|
|
164
|
+
button.on:hover { filter: brightness(1.12); background: var(--accent-solid); color: #fff; border-color: transparent; }
|
|
165
|
+
#refresh, #notifyBtn { width: 36px; padding: 0; } /* négyzetes ikon-gomb */
|
|
166
|
+
button svg, .ico { flex: none; }
|
|
167
|
+
|
|
168
|
+
/* Szegmentált nézetváltó (Kanban / Swimlane / Folyam / Kompakt) */
|
|
169
|
+
.segmented { display: inline-flex; gap: 3px; padding: 3px; border-radius: var(--radius-md); background: var(--panel); border: 1px solid var(--border); height: 36px; }
|
|
170
|
+
.segmented button { height: 100%; padding: 0 13px; border: none; background: transparent; border-radius: 7px; color: var(--muted); box-shadow: none; }
|
|
171
|
+
.segmented button:hover { background: rgba(255,255,255,.05); color: var(--text); border: none; }
|
|
172
|
+
.segmented button.on { background: var(--accent-solid); color: #fff; box-shadow: 0 1px 2px rgba(0,0,0,.35); }
|
|
173
|
+
|
|
174
|
+
.status { display: inline-flex; align-items: center; gap: 8px; padding: 5px 11px; border-radius: var(--radius-full); background: rgba(255,255,255,.04); border: 1px solid var(--border); font: 500 12px var(--mono); color: var(--muted); white-space: nowrap; }
|
|
175
|
+
.dot { width: 7px; height: 7px; border-radius: 50%; background: var(--muted); flex: none; }
|
|
176
|
+
.dot.ok { background: var(--ok); animation: livepulse 2.4s infinite; }
|
|
177
|
+
.dot.err { background: var(--err); box-shadow: 0 0 0 3px color-mix(in srgb, var(--err) 25%, transparent); }
|
|
178
|
+
.dot.idle { background: #d99a3f; }
|
|
179
|
+
.pulse { animation: pulse .55s ease; }
|
|
180
|
+
@keyframes pulse { 0%{transform:scale(.55);opacity:.4} 100%{transform:scale(1);opacity:1} }
|
|
181
|
+
@keyframes livepulse { 0%{box-shadow:0 0 0 0 rgba(70,192,127,.45)} 70%{box-shadow:0 0 0 6px rgba(70,192,127,0)} 100%{box-shadow:0 0 0 0 rgba(70,192,127,0)} }
|
|
182
|
+
|
|
183
|
+
.stats, .controls { display: flex; flex-wrap: wrap; align-items: center; gap: 9px 15px; padding: 10px 20px; background: rgba(15,17,21,.82); backdrop-filter: blur(10px); border-bottom: 1px solid var(--border-soft); }
|
|
184
|
+
.stat { display: inline-flex; align-items: center; gap: 7px; font-size: 12px; font-weight: 500; color: var(--muted); }
|
|
185
|
+
.stat b { color: var(--text-strong); font-size: 13px; font-weight: 600; font-variant-numeric: tabular-nums; }
|
|
186
|
+
.stat .swatch { width: 8px; height: 8px; border-radius: 3px; }
|
|
187
|
+
.sep { width: 1px; align-self: center; height: 20px; background: rgba(255,255,255,.08); }
|
|
188
|
+
/* Eloszlás-sáv: minden státusz saját színű szegmensként, arányosan (a "% kész" helyett). */
|
|
189
|
+
.progress { flex: 1 1 160px; min-width: 130px; height: 8px; background: var(--track); border-radius: 4px; overflow: hidden; display: flex; gap: 2px; }
|
|
190
|
+
.progress > i { display: block; height: 100%; }
|
|
191
|
+
.progress-label { font: 600 12px var(--mono); color: var(--muted); white-space: nowrap; }
|
|
192
|
+
.lbl { font-size: 12px; font-weight: 500; color: var(--muted-2); }
|
|
193
|
+
.ro { display: inline-flex; align-items: center; gap: 7px; font: 500 11.5px var(--font); color: #c9a463; padding: 5px 10px; border-radius: var(--radius-md); background: rgba(224,165,74,.08); border: 1px solid rgba(224,165,74,.2); margin-left: auto; }
|
|
194
|
+
/* Modal-beli kv-sorok (pl. függőség-lista címke + linkek egy sorban). */
|
|
195
|
+
.row { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; margin-bottom: 8px; }
|
|
196
|
+
|
|
197
|
+
/* Ágens-terhelés & szűrő sáv: kollapszibilis fejsorral (a mockup mintája). */
|
|
198
|
+
.agents-wrap { display: flex; flex-direction: column; background: rgba(15,17,21,.82); backdrop-filter: blur(10px); border-bottom: 1px solid var(--border-soft); }
|
|
199
|
+
button.agents-head {
|
|
200
|
+
justify-content: flex-start; height: auto; padding: 9px 20px; gap: 8px; border: none; border-radius: 0;
|
|
201
|
+
background: transparent; box-shadow: none; font: inherit; color: inherit; user-select: none;
|
|
202
|
+
}
|
|
203
|
+
button.agents-head:hover { background: rgba(255,255,255,.03); border: none; color: inherit; }
|
|
204
|
+
.agents-head .count-pill { font: 600 11px var(--mono); padding: 1px 7px; border-radius: 999px; background: rgba(255,255,255,.06); color: var(--muted); }
|
|
205
|
+
.agents-head .chev { display: grid; place-items: center; color: var(--muted-2); transition: transform .15s ease; }
|
|
206
|
+
.agents-wrap.open .agents-head .chev { transform: rotate(180deg); }
|
|
207
|
+
.agents { display: flex; flex-wrap: nowrap; align-items: center; gap: 10px; padding: 0 20px 12px; overflow-x: auto; }
|
|
208
|
+
.agents-wrap:not(.open) .agents { display: none; }
|
|
209
|
+
|
|
210
|
+
/* Ágens-chip (szűrő + terhelés-bar): avatar + név/terhelés-sáv, per-agent színnel. */
|
|
211
|
+
.agent-chip { display: inline-flex; align-items: center; gap: 9px; min-width: 160px; padding: 7px 11px; border-radius: 10px; border: 1px solid var(--border); background: var(--panel); color: var(--muted); cursor: pointer; transition: background .12s ease, border-color .12s ease, color .12s ease; }
|
|
212
|
+
.agent-chip:hover { color: var(--text); }
|
|
213
|
+
/* Aktív (szűrőben megjelenő) chip: lágy accent-tint. */
|
|
214
|
+
.agent-chip.on { background: color-mix(in srgb, var(--accent) 6%, var(--panel)); color: var(--text); }
|
|
215
|
+
.agent-chip .ac-avatar { width: 22px; height: 22px; border-radius: 6px; display: grid; place-items: center; font: 600 10px var(--mono); flex: none; }
|
|
216
|
+
.agent-chip .ac-info { display: flex; flex-direction: column; gap: 5px; flex: 1; min-width: 0; }
|
|
217
|
+
.agent-chip .ac-top { display: flex; align-items: center; justify-content: space-between; gap: 8px; font: 500 12px var(--mono); color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
218
|
+
.agent-chip .ac-count { flex: none; font: 600 11px var(--mono); font-variant-numeric: tabular-nums; color: var(--muted); padding: 0; background: none; }
|
|
219
|
+
.agent-chip .ac-bar { width: 100%; height: 3px; border-radius: 3px; background: rgba(255,255,255,.09); overflow: hidden; }
|
|
220
|
+
.agent-chip .ac-bar > i { display: block; height: 100%; border-radius: 3px; transition: width .3s ease; }
|
|
221
|
+
|
|
222
|
+
.board { display: flex; gap: 14px; padding: 16px 20px 18px; flex: 1 1 0; min-height: 0; align-items: stretch; overflow: auto; }
|
|
223
|
+
.board.swim { flex-direction: column; overflow: hidden auto; align-items: stretch; }
|
|
224
|
+
/* Kanban módban minden oszlop egyforma magas, a tartalom oszloponként belül görög. */
|
|
225
|
+
.board:not(.swim) .col-body { overflow-y: auto; min-height: 0; flex: 1 1 auto; }
|
|
226
|
+
/* A swim-board flex-oszlop; a lane-ek NE zsugorodjanak (különben túlcsordulásnál
|
|
227
|
+
összenyomódnak és a .lane overflow:hidden levágja a tartalmat, görgetés helyett). */
|
|
228
|
+
.board.swim > .lane { flex: 0 0 auto; }
|
|
229
|
+
.lane { border: 1px solid var(--border); border-radius: var(--radius-lg); margin-bottom: 13px; background: var(--panel); overflow: hidden; }
|
|
230
|
+
.lane-head { display: flex; align-items: center; gap: 10px; padding: 12px 14px; font: 500 13px var(--mono); color: var(--text); border-bottom: 1px solid var(--border-soft); }
|
|
231
|
+
.lane-head .mut { color: var(--muted); font-weight: 400; font-size: 12px; }
|
|
232
|
+
.lane-cols { display: flex; gap: 11px; padding: 13px 14px; overflow-x: auto; align-items: flex-start; }
|
|
233
|
+
/* Lane-en belüli oszlopok: könnyed csoportok, nem beágyazott nehéz panelek. */
|
|
234
|
+
.board.swim .col { background: transparent; border: none; border-radius: 0; padding: 0; min-width: 244px; flex: 0 0 244px; }
|
|
235
|
+
.board.swim .col-head { margin: 0 2px 9px; }
|
|
236
|
+
.board.swim .col-body { display: flex; flex-direction: column; gap: 9px; }
|
|
237
|
+
|
|
238
|
+
.col { flex: 1 1 0; min-width: 260px; background: var(--panel); border: 1px solid var(--border-soft); border-radius: var(--radius-lg); padding: 2px 10px 12px; display: flex; flex-direction: column; transition: flex-basis .2s ease, min-width .2s ease; }
|
|
239
|
+
.col.collapsed { flex: 0 0 46px; min-width: 0; }
|
|
240
|
+
/* Adat-vezérelt: az ÜRES Kanban-oszlopok zsugorodjanak. (:has → modern böngésző) */
|
|
241
|
+
.board:not(.swim) .col:not(.collapsed):has(.col-body > .empty) { flex: 0 1 176px; min-width: 156px; }
|
|
242
|
+
.col-head { display: flex; align-items: center; gap: 9px; font: 600 12px var(--font); text-transform: uppercase; letter-spacing: .09em; margin: 13px 4px 11px; color: var(--muted); user-select: none; }
|
|
243
|
+
.col-head .caret { font-size: 9px; color: var(--muted-2); }
|
|
244
|
+
.col-head .swatch { width: 9px; height: 9px; border-radius: 3px; }
|
|
245
|
+
.col-head .col-title { flex: 1 1 auto; }
|
|
246
|
+
.col-head .count { margin-left: auto; background: rgba(255,255,255,.06); color: var(--muted); border-radius: var(--radius-full); padding: 2px 8px; font: 600 11px var(--mono); font-variant-numeric: tabular-nums; }
|
|
247
|
+
.col.collapsed { padding: 2px; }
|
|
248
|
+
.col.collapsed .col-head { writing-mode: vertical-rl; transform: rotate(180deg); margin: 8px auto; height: 150px; gap: 8px; }
|
|
249
|
+
.col.collapsed .col-head .count { margin: 0; }
|
|
250
|
+
.col.collapsed .col-body { display: none; }
|
|
251
|
+
|
|
252
|
+
.card {
|
|
253
|
+
position: relative; background: var(--card); border: 1px solid var(--border);
|
|
254
|
+
border-left: 3px solid var(--border); border-radius: 12px;
|
|
255
|
+
padding: 13px 14px 12px; margin-bottom: 9px; cursor: pointer;
|
|
256
|
+
transition: background .12s ease, border-color .12s ease, transform .12s ease, box-shadow .15s ease;
|
|
257
|
+
}
|
|
258
|
+
.card:hover { background: var(--card-hover); border-color: var(--border-strong); transform: translateY(-1px); box-shadow: var(--shadow-lg); }
|
|
259
|
+
.card:active { transform: translateY(0); }
|
|
260
|
+
.card.changed { animation: flash 1.8s ease; }
|
|
261
|
+
@keyframes flash { 0%,15% { box-shadow: inset 0 0 0 1.5px var(--accent), var(--shadow-lg); } 100% { box-shadow: none; } }
|
|
262
|
+
.badges { display: flex; flex-wrap: wrap; gap: 5px; margin-bottom: 9px; }
|
|
263
|
+
.badge { display: inline-flex; align-items: center; gap: 4px; line-height: 1; font: 600 10px var(--mono); letter-spacing: .04em; padding: 4px 8px; border-radius: var(--radius-sm); border: 1px solid var(--border); background: var(--panel-2); color: var(--muted); }
|
|
264
|
+
.badge.team { background: var(--accent-solid); color: #fff; border-color: transparent; }
|
|
265
|
+
.badge.module { background: transparent; }
|
|
266
|
+
.badge.ch { background: var(--accent-tint-bg); color: var(--accent-tint-text); border-color: transparent; }
|
|
267
|
+
.badge.dep-active { background: var(--danger-bg); color: var(--danger-text); border-color: var(--danger-border); cursor: pointer; transition: filter .12s ease; }
|
|
268
|
+
.badge.dep-done { opacity: .6; text-decoration: line-through; cursor: pointer; transition: filter .12s ease, opacity .12s ease; }
|
|
269
|
+
.badge.dep-active:hover, .badge.dep-done:hover { filter: brightness(1.2); }
|
|
270
|
+
.badge.dep-done:hover { opacity: .85; }
|
|
271
|
+
.card h3 { margin: 0 0 7px; font: 600 14.5px/1.35 var(--font); letter-spacing: -.005em; color: #eceef1; }
|
|
272
|
+
.card .desc { color: #8b929c; font: 400 12.5px/1.55 var(--font); margin: 0 0 12px; display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; }
|
|
273
|
+
.card .meta { display: flex; flex-wrap: wrap; gap: 6px 8px; align-items: center; }
|
|
274
|
+
.tag { display: inline-flex; align-items: center; gap: 5px; line-height: 1; font: 500 11px var(--mono); padding: 4px 8px; border-radius: var(--radius-sm); background: var(--panel-2); color: var(--muted); border: 1px solid var(--border); }
|
|
275
|
+
.tag.agent { color: var(--text); font-weight: 600; }
|
|
276
|
+
/* Kis agent-avatar (kártyán és kész-soron egyaránt) — per-agent szín, a mockup mintája. */
|
|
277
|
+
.who-av { display: inline-flex; align-items: center; justify-content: center; width: 16px; height: 16px; border-radius: 5px; font: 600 8.5px var(--mono); flex: none; }
|
|
278
|
+
/* A kártyán a blocked-jegyzet: max 3 sor; a teljes szöveg a modalban. */
|
|
279
|
+
.note { margin-top: 11px; font: 500 11px var(--font); color: var(--danger-text); background: var(--danger-bg); border: 1px solid var(--danger-border); border-radius: 7px; padding: 5px 10px; line-height: 1.45; display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; }
|
|
280
|
+
/* Kompakt kártya-nézet */
|
|
281
|
+
.board.compact .card { padding: 8px 12px; }
|
|
282
|
+
.board.compact .card .desc, .board.compact .card .note { display: none; }
|
|
283
|
+
.board.compact .card h3 { font-size: 13px; margin-bottom: 4px; -webkit-line-clamp: 2; display: -webkit-box; -webkit-box-orient: vertical; overflow: hidden; }
|
|
284
|
+
|
|
285
|
+
/* Kész taszkok karcsú sora (a mockup "isDone" kártya-variánsa): nincs leírás/badge,
|
|
286
|
+
csak ellenőrzőjel-avatar + cím + agent + idő egy vízszintes sorban. */
|
|
287
|
+
.card.card-done { display: flex; align-items: center; gap: 11px; padding: 9px 12px; background: #161a20; border-left: 1px solid var(--border-soft); }
|
|
288
|
+
.card.card-done:hover { background: #1a1f27; border-color: color-mix(in srgb, var(--done) 24%, var(--border)); transform: none; box-shadow: none; }
|
|
289
|
+
.done-check { width: 24px; height: 24px; border-radius: 7px; display: grid; place-items: center; background: color-mix(in srgb, var(--done) 12%, transparent); border: 1px solid color-mix(in srgb, var(--done) 26%, transparent); color: var(--done); flex: none; }
|
|
290
|
+
.card-done-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 4px; }
|
|
291
|
+
.card-done-title { display: flex; align-items: center; gap: 8px; min-width: 0; }
|
|
292
|
+
.card-done-title .badges-inline { display: inline-flex; gap: 4px; flex: none; }
|
|
293
|
+
.card-done-title .title-txt { font: 500 13px/1.3 var(--font); color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; flex: 1; min-width: 0; }
|
|
294
|
+
.card-done-meta { display: flex; align-items: center; gap: 7px; min-width: 0; font: 500 11px var(--mono); color: var(--muted-2); }
|
|
295
|
+
.card-done-meta .who-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--muted); }
|
|
296
|
+
.card-done-meta .dot-sep { width: 3px; height: 3px; border-radius: 50%; background: #454b55; flex: none; }
|
|
297
|
+
.board.compact .card.card-done { padding: 6px 10px; }
|
|
298
|
+
|
|
299
|
+
.empty { color: #4b515c; font: 500 12px var(--mono); text-align: center; padding: 22px 6px; margin: 6px 0; border: 1px dashed rgba(255,255,255,.08); border-radius: 11px; }
|
|
300
|
+
.banner { margin: 12px 20px 0; padding: 12px 16px; border-radius: var(--radius-md); background: var(--danger-bg); border: 1px solid var(--danger-border); color: var(--danger-text); font-size: 12.5px; display: none; }
|
|
301
|
+
.banner.show { display: block; }
|
|
302
|
+
code { background: var(--panel-2); border: 1px solid var(--border); padding: 2px 6px; border-radius: var(--radius-sm); font: 500 12px var(--mono); }
|
|
303
|
+
|
|
304
|
+
/* Modal */
|
|
305
|
+
.overlay { position: fixed; inset: 0; background: rgba(6,8,11,.66); backdrop-filter: blur(6px); display: none; align-items: flex-start; justify-content: center; padding: 48px 16px; z-index: 50; overflow-y: auto; }
|
|
306
|
+
.overlay.show { display: flex; }
|
|
307
|
+
.modal { background: var(--panel); border-radius: var(--radius-lg); box-shadow: var(--shadow-modal); width: min(700px, 100%); border: 1px solid var(--border); }
|
|
308
|
+
.modal header { position: static; border-radius: var(--radius-lg) var(--radius-lg) 0 0; background: transparent; backdrop-filter: none; border-bottom: 1px solid var(--border-soft); }
|
|
309
|
+
.modal h2 { font-size: 16px; font-weight: 600; margin: 0; display: flex; align-items: center; gap: 8px; flex-wrap: wrap; color: var(--text-strong); }
|
|
310
|
+
.modal .body { padding: 20px 22px; }
|
|
311
|
+
.modal .close { margin-left: auto; }
|
|
312
|
+
.modal .desc-full { white-space: pre-wrap; font-size: 13.5px; line-height: 1.6; margin: 0 0 16px; }
|
|
313
|
+
.modal h4 { font: 600 12px var(--font); text-transform: uppercase; letter-spacing: .07em; color: var(--muted-2); margin: 18px 0 10px; }
|
|
314
|
+
.kv { display: grid; grid-template-columns: max-content 1fr; gap: 6px 14px; font-size: 12.5px; margin-bottom: 10px; }
|
|
315
|
+
.kv dt { color: var(--muted); }
|
|
316
|
+
.kv dd { margin: 0; word-break: break-word; }
|
|
317
|
+
.copy-id { margin-left: 6px; padding: 1px 7px; font-size: 11px; line-height: 1.5; vertical-align: baseline; border-radius: var(--radius-full); }
|
|
318
|
+
.copy-id.copied { background: var(--accent-solid); color: #fff; border-color: transparent; }
|
|
319
|
+
.metrics { display: flex; flex-wrap: wrap; gap: 10px; }
|
|
320
|
+
.metric { background: var(--panel-2); border: 1px solid var(--border-soft); border-radius: 10px; padding: 10px 14px; font-size: 12.5px; }
|
|
321
|
+
.metric b { display: block; font-size: 16px; font-variant-numeric: tabular-nums; }
|
|
322
|
+
.deplinks { display: flex; flex-wrap: wrap; gap: 7px; }
|
|
323
|
+
.deplink { cursor: pointer; }
|
|
324
|
+
|
|
325
|
+
/* --- Interaktív akció-sáv a modalban (írás a router.php bridge-en át) --- */
|
|
326
|
+
.actions { display: flex; flex-direction: column; gap: 10px; padding: 14px; margin: 0 0 16px; background: var(--panel-2); border: 1px solid var(--border-soft); border-radius: var(--radius-md); }
|
|
327
|
+
.act-row { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
|
|
328
|
+
.act-btn { height: 32px; padding: 0 13px; font: 600 12px var(--font); }
|
|
329
|
+
.act-btn.act-approve { background: color-mix(in srgb, var(--ok) 15%, var(--panel)); border-color: color-mix(in srgb, var(--ok) 45%, transparent); color: var(--ok); }
|
|
330
|
+
.act-btn.act-approve:hover { background: color-mix(in srgb, var(--ok) 24%, var(--panel)); color: #fff; }
|
|
331
|
+
.act-btn.act-changes { background: rgba(224,165,74,.1); border-color: rgba(224,165,74,.34); color: #d8a24a; }
|
|
332
|
+
.act-btn.act-changes:hover { background: rgba(224,165,74,.2); color: #fff; }
|
|
333
|
+
.act-btn.act-block { background: var(--danger-bg); border-color: var(--danger-border); color: var(--danger-text); }
|
|
334
|
+
.act-btn.act-block:hover { background: color-mix(in srgb, var(--err) 24%, var(--panel)); color: #fff; }
|
|
335
|
+
.act-note { width: 100%; resize: vertical; min-height: 42px; padding: 8px 11px; font: 400 12.5px var(--font); line-height: 1.5; color: var(--text); background: var(--panel); border: 1px solid var(--border); border-radius: var(--radius-sm); }
|
|
336
|
+
.act-note:focus-visible { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 26%, transparent); }
|
|
337
|
+
.act-fields { justify-content: flex-start; }
|
|
338
|
+
.act-field { display: inline-flex; align-items: center; gap: 6px; font: 500 11.5px var(--mono); color: var(--muted); }
|
|
339
|
+
.act-field .act-input { height: 30px; }
|
|
340
|
+
.act-field select.act-input { padding: 0 8px; }
|
|
341
|
+
.act-field input.act-input { width: 150px; padding: 0 10px; }
|
|
342
|
+
/* Jegyzetek a modalban: időbélyeges, típus-taggelt kártyák. */
|
|
343
|
+
ul.notes { list-style: none; margin: 0; padding: 0; font-size: 12.5px; }
|
|
344
|
+
ul.notes li { margin-bottom: 8px; }
|
|
345
|
+
ul.notes li.note-item { border: 1px solid var(--border); border-radius: 10px; padding: 9px 12px; background: var(--panel-2); }
|
|
346
|
+
.note-item .n-top { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; margin-bottom: 5px; }
|
|
347
|
+
.note-item .n-when { font: 500 11.5px var(--mono); color: var(--muted-2); margin-left: auto; }
|
|
348
|
+
.note-item .n-text { white-space: pre-wrap; line-height: 1.55; }
|
|
349
|
+
/* Jegyzet-fázis badge alakja: modalban (.n-kind) és a kártyán (.kind-badge) is. */
|
|
350
|
+
.n-kind, .kind-badge { display: inline-flex; align-items: center; line-height: 1; font: 700 10px var(--mono); letter-spacing: .05em; text-transform: uppercase; padding: 4px 8px; border-radius: var(--radius-sm); border: 1px solid transparent; white-space: nowrap; }
|
|
351
|
+
.k-research { background: rgba(69,181,196,.16); color: #6fcdda; }
|
|
352
|
+
.k-plan { background: color-mix(in srgb, var(--review) 20%, transparent); color: #c79cf7; }
|
|
353
|
+
.k-decision { background: color-mix(in srgb, var(--in_progress) 20%, transparent); color: #7db0f9; }
|
|
354
|
+
.k-impl { background: color-mix(in srgb, var(--done) 18%, transparent); color: #6fce9d; }
|
|
355
|
+
.k-other { background: rgba(255,255,255,.06); color: var(--muted); }
|
|
356
|
+
.timeline { list-style: none; margin: 0; padding: 0; }
|
|
357
|
+
.timeline li { position: relative; padding: 0 0 16px 22px; border-left: 2px solid var(--border); }
|
|
358
|
+
.timeline li:last-child { border-left-color: transparent; }
|
|
359
|
+
.timeline li::before { content: ""; position: absolute; left: -6px; top: 2px; width: 10px; height: 10px; border-radius: 50%; background: var(--accent); box-shadow: 0 0 0 2px var(--panel); }
|
|
360
|
+
.timeline .when { font: 500 11.5px var(--mono); color: var(--muted-2); }
|
|
361
|
+
.timeline .trans { font-size: 12.5px; margin: 2px 0; }
|
|
362
|
+
.timeline .note2 { font-size: 12px; color: var(--muted); }
|
|
363
|
+
.pill { display: inline-flex; align-items: center; line-height: 1; font: 600 11px var(--mono); padding: 4px 9px; border-radius: var(--radius-sm); color: var(--pill-fg-light); }
|
|
364
|
+
.pill.pill-dark { color: var(--pill-fg-dark); }
|
|
365
|
+
.mut { color: var(--muted); font-weight: 400; font-size: 12px; }
|
|
366
|
+
#ctxBtn.has::after { content: attr(data-n); margin-left: 6px; background: var(--accent-solid); color: #fff; border-radius: var(--radius-full); padding: 0 6px; font: 600 11px var(--mono); }
|
|
367
|
+
.ctx-quote { background: var(--panel-2); border: 1px solid var(--border-soft); border-left: 3px solid var(--accent); border-radius: 8px; padding: 10px 12px; white-space: pre-wrap; font-size: 13px; line-height: 1.55; margin: 0 0 8px; }
|
|
368
|
+
.ctx-list { margin: 0; padding-left: 18px; font-size: 13px; }
|
|
369
|
+
.ctx-list li { margin-bottom: 5px; }
|
|
370
|
+
.decision { border: 1px solid var(--border); border-radius: 10px; padding: 10px 12px; margin-bottom: 8px; }
|
|
371
|
+
.decision .d-top { display: flex; flex-wrap: wrap; gap: 6px 10px; align-items: baseline; margin-bottom: 3px; }
|
|
372
|
+
.decision .d-topic { font-weight: 600; font-size: 13px; }
|
|
373
|
+
.decision .d-when { font: 500 11.5px var(--mono); color: var(--muted-2); margin-left: auto; }
|
|
374
|
+
.decision .d-rat { font-size: 12px; color: var(--muted); margin-top: 3px; }
|
|
375
|
+
|
|
376
|
+
/* ---- #1 „Rád vár" kor-badge (review): eszkalálódó hangsúly a várakozás hosszával ---- */
|
|
377
|
+
.badge.await { border-color: transparent; }
|
|
378
|
+
.badge.await-fresh { background: color-mix(in srgb, var(--review) 20%, transparent); color: #c79cf7; }
|
|
379
|
+
.badge.await-warn { background: rgba(224,166,63,.2); color: #e9b866; }
|
|
380
|
+
.badge.await-stale { background: var(--danger-bg); color: var(--danger-text); border-color: var(--danger-border); animation: awaitPulse 2.4s ease-in-out infinite; }
|
|
381
|
+
@keyframes awaitPulse { 0%,100% { box-shadow: 0 0 0 0 transparent; } 50% { box-shadow: 0 0 0 3px color-mix(in srgb, var(--err) 26%, transparent); } }
|
|
382
|
+
|
|
383
|
+
/* ---- #5 Gyorsszűrő-chipek (az .on állapotot a globális button.on adja) ---- */
|
|
384
|
+
button.qf { padding: 6px 11px; font-size: 12px; }
|
|
385
|
+
|
|
386
|
+
/* ---- #2 Aktivitás-folyam nézet ---- */
|
|
387
|
+
.board.feed { flex-direction: column; overflow: hidden auto; align-items: stretch; gap: 10px; padding: 18px 20px 36px; }
|
|
388
|
+
.board.feed { max-width: 1180px; margin: 0 auto; width: 100%; }
|
|
389
|
+
.board.feed > .feed-item { flex: 0 0 auto; }
|
|
390
|
+
.feed-item { position: relative; background: #13161c; border: 1px solid var(--border-soft); border-radius: 12px; padding: 13px 18px 14px; overflow: hidden; cursor: pointer; transition: border-color .12s ease, background .12s ease; }
|
|
391
|
+
.feed-item:hover { border-color: var(--border-strong); background: #151920; }
|
|
392
|
+
.fi-top { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
|
|
393
|
+
.fi-type { font: 600 10.5px var(--mono); letter-spacing: .09em; color: var(--muted-2); text-transform: uppercase; }
|
|
394
|
+
.fi-task { font: 600 14px var(--font); letter-spacing: -.005em; color: #e9ebee; flex: 1; min-width: 180px; }
|
|
395
|
+
.fi-when { margin-left: auto; font: 500 11.5px var(--mono); color: var(--muted-2); white-space: nowrap; }
|
|
396
|
+
.fi-text { margin-top: 9px; font: 400 13px/1.6 var(--font); color: #8b929c; white-space: pre-wrap; display: -webkit-box; -webkit-line-clamp: 4; -webkit-box-orient: vertical; overflow: hidden; }
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: task-manager
|
|
3
|
+
description: Capture actionable user requests as persistent tasks, update task status as work progresses, and keep a shared task store in sync. Use when a user asks an agent to do work, check progress, block a task, complete a task, or manage the Kanban board.
|
|
4
|
+
metadata: {"openclaw":{"skillKey":"task-manager"}}
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Task Manager (__PROJECT_LABEL__)
|
|
8
|
+
|
|
9
|
+
Use this skill for task capture and task lifecycle updates in this project ("__PROJECT_ID__").
|
|
10
|
+
|
|
11
|
+
This folder was generated by the **claude-task-manager** installer (`install.sh`) — the real
|
|
12
|
+
table (tasks.json/context.json/events.jsonl) lives under the claude-task-manager project, in
|
|
13
|
+
`data/__PROJECT_ID__/`, NOT in this project. The `task.sh` here is a **wrapper**
|
|
14
|
+
that targets that data directory — the calling pattern otherwise stays exactly the
|
|
15
|
+
same as before.
|
|
16
|
+
|
|
17
|
+
## Trigger
|
|
18
|
+
|
|
19
|
+
```json
|
|
20
|
+
{
|
|
21
|
+
"activation": {
|
|
22
|
+
"anyPhrases": [
|
|
23
|
+
"add a task",
|
|
24
|
+
"create a task",
|
|
25
|
+
"track this task",
|
|
26
|
+
"task status",
|
|
27
|
+
"mark this done",
|
|
28
|
+
"block this task",
|
|
29
|
+
"what tasks do we have"
|
|
30
|
+
]
|
|
31
|
+
},
|
|
32
|
+
"movement": {
|
|
33
|
+
"target": "desk",
|
|
34
|
+
"skipIfAlreadyThere": true
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Also use this skill even when those exact phrases are absent if the latest user message is an actionable work request. If the user asks the agent to do something, that request must become a task before the agent proceeds.
|
|
40
|
+
|
|
41
|
+
## Storage location
|
|
42
|
+
|
|
43
|
+
The authoritative store lives under the **claude-task-manager** project (not in this repo):
|
|
44
|
+
|
|
45
|
+
- `data/__PROJECT_ID__/tasks.json` — the Kanban board (source of truth for tasks).
|
|
46
|
+
- `data/__PROJECT_ID__/context.json` — the **user context** (source of truth for the user's intent, decisions, and init prompt; see "User context" below).
|
|
47
|
+
|
|
48
|
+
NEVER read/write these files directly from this project — always go through the `task.sh`
|
|
49
|
+
wrapper below (it resolves the correct data directory).
|
|
50
|
+
|
|
51
|
+
## Token-efficient CLI (`task.sh`) — THE ONLY WRITER
|
|
52
|
+
|
|
53
|
+
For handling `tasks.json`, **do not** re-read/rewrite the whole file (it costs a lot of
|
|
54
|
+
tokens). Use the `task.sh` wrapper bundled with the skill (jq-based), which produces
|
|
55
|
+
compact output and writes atomically (it automatically maintains the timestamp and
|
|
56
|
+
history/notes entries). The script is on the Claude settings allowlist and can run
|
|
57
|
+
without a permission prompt.
|
|
58
|
+
|
|
59
|
+
> **HARD RULE — NEVER edit the JSON directly; only use `task.sh`.** Do not modify either
|
|
60
|
+
> `tasks.json` or `context.json` with the `Write`/`Edit` tools, and do not write back "the
|
|
61
|
+
> full JSON" by hand. Every mutation (both task AND context) must go **exclusively**
|
|
62
|
+
> through `task.sh` commands — this way there is a single atomic writer, with consistent
|
|
63
|
+
> timestamps and history, and no corrupted/duplicated state. This applies to the **main
|
|
64
|
+
> agent and EVERY subagent/teammate**. For reads, use `task.sh`'s query commands
|
|
65
|
+
> (`summary`, `list`, `get`, `ctx` …); only use `Read` on the JSON as a last resort, and
|
|
66
|
+
> never to write. (For `context.json`, use the `ctx-*` commands — see below.)
|
|
67
|
+
|
|
68
|
+
Canonical calling form (with the FULL absolute path, from any working directory):
|
|
69
|
+
|
|
70
|
+
```
|
|
71
|
+
__TASK_SH_PATH__ <command> [args] --as <agent>
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
> **REQUIRED: `--as <agent>` on every non-meta command.** Add your own name to every
|
|
75
|
+
> `task.sh` call: the **main agent uses `--as main`**, a teammate uses its own label
|
|
76
|
+
> (`--as backend-auth`). This is recorded as the `by` field on every event. Without
|
|
77
|
+
> `--as`, non-meta commands **throw an error**. Exceptions (no `--as` needed): `help`,
|
|
78
|
+
> `inbox`, `init`, `validate`, `restore`, `raw`.
|
|
79
|
+
|
|
80
|
+
> **No permission prompt needed — call it DIRECTLY, as a bare command.** ALWAYS call
|
|
81
|
+
> `task.sh` with the absolute path above, as a **standalone** command — no `cd`,
|
|
82
|
+
> `&&`/`||`, redirects (`2>&1`), or `$VARIABLE`. Claude Code requires a permission
|
|
83
|
+
> prompt for chained commands **segment by segment**, so a `cd … && …task.sh …` form
|
|
84
|
+
> would trigger a prompt. The script already has `TM_DIR` baked into itself (see
|
|
85
|
+
> `claude-task-manager/engine/projects.sh`), so `cd` is unnecessary anyway. The script
|
|
86
|
+
> is on the project allowlist (`.claude/settings.local.json`, `Bash(…task.sh:*)`), so
|
|
87
|
+
> the bare absolute call runs without a permission prompt.
|
|
88
|
+
|
|
89
|
+
Most common commands (always call with the FULL absolute path — copy it as shown):
|
|
90
|
+
|
|
91
|
+
- `__TASK_SH_PATH__ summary --as main` — counts by status (a quick "where do we stand" overview).
|
|
92
|
+
- `__TASK_SH_PATH__ list [status] --as main` — compact list in `id [status] title` form.
|
|
93
|
+
- `__TASK_SH_PATH__ get <id> --as main` — the full JSON of a SINGLE task (not the whole file).
|
|
94
|
+
- `__TASK_SH_PATH__ add <id> <title> [desc] --as main` — a new task with `todo` status, with all required fields.
|
|
95
|
+
- `__TASK_SH_PATH__ status <id> <status> [note] --as main` — status change + history entry.
|
|
96
|
+
- `__TASK_SH_PATH__ note <id> <text> --as main` — append a note.
|
|
97
|
+
- `__TASK_SH_PATH__ set <id> <field> <json-value> --as main` — set an arbitrary field (quote strings like `'"main"'`).
|
|
98
|
+
- `__TASK_SH_PATH__ find <text> --as main` — and likewise: `… history <id>`, `… ids`, `… archive|unarchive|rm <id>`.
|
|
99
|
+
|
|
100
|
+
**Structured fields and workflow commands** (instead of encoding them into title/notes text):
|
|
101
|
+
|
|
102
|
+
- `… priority <id> <low|normal|high|urgent>` — priority.
|
|
103
|
+
- `… tag <id> <add|rm> <tag>` — tags (e.g. `frontend`/`backend`/`test`).
|
|
104
|
+
- `… assign <id> <agent>` — sets `assignedAgentId` (more convenient than `set` for claiming).
|
|
105
|
+
- `… dep <id> <add|rm> <other-id>` — dependency (`dependsOn`): `id` waits on `other-id`; includes cycle and existence checks.
|
|
106
|
+
- `… deps <id>` — what this task is waiting on and what it blocks.
|
|
107
|
+
- `… next` — the next recommended `todo` task (no open dependency), sorted by priority.
|
|
108
|
+
- `… list [status] --tag <t> --agent <a> --priority <p> --all --json` — filtered/machine-readable list.
|
|
109
|
+
- `… status-many <status> <id...>` — move multiple tasks to one status in a SINGLE atomic write.
|
|
110
|
+
- `… reopen <id> [status]` — reopen a closed/archived task.
|
|
111
|
+
- `… validate` — schema check (required fields, status, priority, broken dependencies, duplicate ids).
|
|
112
|
+
- `… restore` — restore the most recent pre-write backup (`tasks.json.bak`).
|
|
113
|
+
- `… inbox <agent>` — events generated by OTHER agents since `<agent>`'s cursor (meta command, no `--as`).
|
|
114
|
+
|
|
115
|
+
Full help: `__TASK_SH_PATH__ help`. Only read the full JSON (`… raw` / Read) if the task
|
|
116
|
+
cannot be accomplished with the commands above.
|
|
117
|
+
|
|
118
|
+
## User context (session continuity)
|
|
119
|
+
|
|
120
|
+
Beyond individual tasks, maintain a durable **user context** so that work can be resumed in a
|
|
121
|
+
**fresh session** without re-interviewing the user. Store it (via `task.sh`'s `ctx-*`
|
|
122
|
+
commands) — never with `Write`/`Edit`:
|
|
123
|
+
|
|
124
|
+
- Session starts and the file is missing → `ctx-init "<initPrompt>" "<goal>" --as main`.
|
|
125
|
+
- The user makes a **decision** → `ctx-decision "<topic>" "<decision>" "<rationale>" --as main`.
|
|
126
|
+
- A permanent rule/constraint is stated → `ctx-constraint "<text>" --as main`.
|
|
127
|
+
- An open question arises / is resolved → `ctx-question add|rm "<text>" --as main`.
|
|
128
|
+
- The active focus changes → `ctx-set currentFocus '"<task-id or text>"' --as main`.
|
|
129
|
+
|
|
130
|
+
At the start of every session, **read `task.sh ctx` first**, and let it guide the work.
|
|
131
|
+
|
|
132
|
+
## Required workflow
|
|
133
|
+
|
|
134
|
+
Every step goes through `task.sh` (never a direct JSON write). **Add `--as main` to
|
|
135
|
+
every non-meta command** (as the main agent); a teammate uses its own `--as <name>`:
|
|
136
|
+
|
|
137
|
+
1. Before handling an actionable request, `task.sh summary --as main` / `list … --as main`.
|
|
138
|
+
2. At session start, `task.sh ctx --as main`; if missing, `ctx-init "<initPrompt>" "<goal>" --as main`.
|
|
139
|
+
3. If the last user message is actionable and there's no active task for it, immediately `task.sh add <id> "<title>" "<desc>" --as main`.
|
|
140
|
+
4. Before starting work, the task should be `todo`, or run `task.sh status <id> in_progress --as main`.
|
|
141
|
+
5. If the work cannot proceed, `task.sh status <id> blocked "<reason>" --as main`.
|
|
142
|
+
6. When done, `task.sh status <id> done --as main`.
|
|
143
|
+
7. If user review/confirmation is needed, `task.sh status <id> review --as main`.
|
|
144
|
+
8. `task.sh` writes every mutation atomically and maintains the timestamp/history — manually
|
|
145
|
+
writing back the full JSON is unnecessary and forbidden.
|
|
146
|
+
|
|
147
|
+
## Status rules
|
|
148
|
+
|
|
149
|
+
- New actionable requests start as `todo` unless work has already begun.
|
|
150
|
+
- Move to `in_progress` when the agent is actively working.
|
|
151
|
+
- Move to `blocked` when progress depends on missing input, credentials, approvals, or failures.
|
|
152
|
+
- Move to `review` when the work is ready for inspection or handoff.
|
|
153
|
+
- Move to `done` only when the requested work is complete.
|
|
154
|
+
|
|
155
|
+
## Board (shared, dockerized interface)
|
|
156
|
+
|
|
157
|
+
The board is served by the **claude-task-manager** project (docker compose, port 3333),
|
|
158
|
+
a **shared** interface for all installed projects — select this project
|
|
159
|
+
(**__PROJECT_LABEL__**) from the "Source" picker in the header:
|
|
160
|
+
|
|
161
|
+
```
|
|
162
|
+
cd /Users/mgeri1993/code/projects/claude-task-manager && docker compose up -d
|
|
163
|
+
# then: http://localhost:3333/
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
Writes from the board **still go through `task.sh`** (the single-writer invariant is
|
|
167
|
+
preserved: atomic lock, history, `events.jsonl`, inbox) — the browser NEVER writes the
|
|
168
|
+
JSON directly. `task.sh` calls (agent work) **don't need docker** — the
|
|
169
|
+
`__TASK_SH_PATH__` above is a plain host bash script that runs standalone.
|
|
170
|
+
|
|
171
|
+
## Related
|
|
172
|
+
|
|
173
|
+
- Teammate coordination (Agent Teams / FleetView), SendMessage-based mid-flight
|
|
174
|
+
direction, `review → main decides (done | assign+todo)` handoff loop — this is the
|
|
175
|
+
same general pattern used in any project that uses `task.sh`; not repeated here.
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: "ctm-backend-developer"
|
|
3
|
+
description: "Task-manager teammate: BACKEND developer (__PROJECT_LABEL__ project). Claims and updates the status of its own tasks with task.sh. This definition describes ONLY the task-manager workflow (when and how to run task.sh)."
|
|
4
|
+
tools: Read, Write, Edit, Bash, Glob, Grep, SendMessage, mcp__ide__getDiagnostics
|
|
5
|
+
model: sonnet
|
|
6
|
+
color: blue
|
|
7
|
+
memory: project
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
<!-- Auto-generated from: claude-task-manager/templates/agents/ctm-backend-developer.md.tmpl — to reinstall: ctm init -->
|
|
11
|
+
|
|
12
|
+
You are the **backend-developer** teammate on the __PROJECT_LABEL__ project. Your name in the task manager (`--as` and `assign` target) is: **`backend-developer`**. You handle backend tasks — the specific language/framework and folder structure can be found in the project's own documentation (README, CLAUDE.md, docs/); this definition is deliberately NOT loaded with project-specific details.
|
|
13
|
+
|
|
14
|
+
This document records **only the task-manager workflow**: when and how to run `task.sh`. You take the backend conventions (language, framework, database/migration rules, if documented) from the project's own documentation and the task description — **if the project's CLAUDE.md or other documentation states a constraint (e.g. a migration/seed ban), always follow it.**
|
|
15
|
+
|
|
16
|
+
## task.sh — calling rules (REQUIRED)
|
|
17
|
+
|
|
18
|
+
- Call it with an **absolute path, as a bare command**, always in a standalone Bash call:
|
|
19
|
+
`__TASK_SH_PATH__ <command> ... --as backend-developer`
|
|
20
|
+
- **NEVER** append `cd`, `&&`/`||`, redirects, or variable substitution.
|
|
21
|
+
- **Every non-meta command needs `--as backend-developer`**.
|
|
22
|
+
- Write `tasks.json` **ONLY** through `task.sh` — never with Read/Edit/Write.
|
|
23
|
+
|
|
24
|
+
## Which tasks are yours
|
|
25
|
+
|
|
26
|
+
- Ones where `assignedAgentId == "backend-developer"`, OR that have the `backend` tag, OR that main assigned to you.
|
|
27
|
+
- Do not touch `frontend-developer`/`code-investigator` tasks.
|
|
28
|
+
|
|
29
|
+
## The work cycle (claim → work → report)
|
|
30
|
+
|
|
31
|
+
1. **What should I pick up?**
|
|
32
|
+
`task.sh list todo --agent backend-developer --as backend-developer`
|
|
33
|
+
`task.sh next --as backend-developer`
|
|
34
|
+
2. **Don't start a blocked task.** Backend work often builds on investigation — let `code-investigator` close it first:
|
|
35
|
+
`task.sh deps <id> --as backend-developer`
|
|
36
|
+
3. **Claim:**
|
|
37
|
+
`task.sh assign <id> backend-developer --as backend-developer`
|
|
38
|
+
`task.sh status <id> in_progress "started" --as backend-developer`
|
|
39
|
+
4. **Work** within your scope, according to the project's own conventions. During fan-out, **do not** run a build/test/formatter per file — just edit + use read-only `mcp__ide__getDiagnostics`; main runs it once, serially.
|
|
40
|
+
5. **Report in a note** — what you changed (file + line), and whether any database change is needed (if the project's rules forbid it, note that too), or whether it was code-only:
|
|
41
|
+
`task.sh note <id> "EventSaveService.php:669 skip condition extended ...; code-only change" --as backend-developer`
|
|
42
|
+
(Avoid backticks and `$` in the note.)
|
|
43
|
+
6. **Closing — ALWAYS `review`, NEVER `done`:** at the end of your part, put the task into `review`, and describe in the note what you changed (file:line) or — if it was analysis only — why no code change was needed, and what's still left. **Main decides** whether it becomes `done` and any further handoff, after checking the review.
|
|
44
|
+
`task.sh status <id> review "my BE part is done — see note" --as backend-developer`
|
|
45
|
+
Put it into `review` even if you think it's fully done (or no change was needed) — main closes it as `done`.
|
|
46
|
+
7. **When a new sub-task comes up** (e.g. a risk you discovered), add it as a separate task, don't fold it into the current one:
|
|
47
|
+
`task.sh add <new-id> "<title>" "<description>" --as backend-developer`
|
|
48
|
+
`task.sh assign <new-id> backend-developer --as backend-developer`
|
|
49
|
+
|
|
50
|
+
## Collaboration
|
|
51
|
+
|
|
52
|
+
- **Main** coordinates. If your queue is empty, notify main (`SendMessage`).
|
|
53
|
+
- Always update status via `task.sh` — other agents are notified of this via the inbox.
|