workstream-cli 0.0.1__py3-none-any.whl

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.
Files changed (86) hide show
  1. workstream/ARCHITECTURE.md +89 -0
  2. workstream/__init__.py +8 -0
  3. workstream/cli.py +136 -0
  4. workstream/commands/__init__.py +0 -0
  5. workstream/commands/backfill.py +139 -0
  6. workstream/commands/block.py +93 -0
  7. workstream/commands/checkin.py +51 -0
  8. workstream/commands/cron.py +119 -0
  9. workstream/commands/focus_cmd.py +273 -0
  10. workstream/commands/idea.py +172 -0
  11. workstream/commands/index.py +89 -0
  12. workstream/commands/init.py +567 -0
  13. workstream/commands/inspect_cmd.py +354 -0
  14. workstream/commands/list_cmd.py +99 -0
  15. workstream/commands/nest.py +108 -0
  16. workstream/commands/new.py +95 -0
  17. workstream/commands/next_cmd.py +333 -0
  18. workstream/commands/report.py +190 -0
  19. workstream/commands/resume.py +145 -0
  20. workstream/commands/review.py +227 -0
  21. workstream/commands/serve.py +23 -0
  22. workstream/commands/setup.py +178 -0
  23. workstream/commands/show.py +123 -0
  24. workstream/commands/snooze.py +117 -0
  25. workstream/commands/stale.py +116 -0
  26. workstream/commands/sweep.py +1753 -0
  27. workstream/commands/tree.py +105 -0
  28. workstream/commands/update_status.py +117 -0
  29. workstream/config.py +322 -0
  30. workstream/extensions/__init__.py +0 -0
  31. workstream/extensions/workstream.ts +633 -0
  32. workstream/focus_artifact.py +157 -0
  33. workstream/git.py +194 -0
  34. workstream/harness.py +49 -0
  35. workstream/llm.py +78 -0
  36. workstream/markdown.py +501 -0
  37. workstream/models.py +274 -0
  38. workstream/plan_index.py +88 -0
  39. workstream/provisioning.py +196 -0
  40. workstream/repo_discovery.py +158 -0
  41. workstream/review_artifact.py +96 -0
  42. workstream/scripts/migrate_statuses.py +120 -0
  43. workstream/skills/__init__.py +0 -0
  44. workstream/skills/workstream_context/SKILL.md +75 -0
  45. workstream/skills/workstream_context/__init__.py +0 -0
  46. workstream/skills/workstream_focus/SKILL.md +141 -0
  47. workstream/skills/workstream_init/SKILL.md +86 -0
  48. workstream/skills/workstream_review/SKILL.md +224 -0
  49. workstream/skills/workstream_sweep/SKILL.md +178 -0
  50. workstream/sweep_state.py +93 -0
  51. workstream/templates/dashboard.html +382 -0
  52. workstream/templates/detail.html +360 -0
  53. workstream/templates/plan.html +210 -0
  54. workstream/test/__init__.py +0 -0
  55. workstream/test/conftest.py +221 -0
  56. workstream/test/fixtures/sample_sprint_note.md +10 -0
  57. workstream/test/fixtures/sample_workstream.md +41 -0
  58. workstream/test/test_backfill.py +180 -0
  59. workstream/test/test_batch_writeback.py +81 -0
  60. workstream/test/test_commands.py +938 -0
  61. workstream/test/test_config.py +54 -0
  62. workstream/test/test_focus_artifact.py +211 -0
  63. workstream/test/test_git.py +88 -0
  64. workstream/test/test_heuristics.py +136 -0
  65. workstream/test/test_hierarchy.py +231 -0
  66. workstream/test/test_init.py +452 -0
  67. workstream/test/test_inspect.py +143 -0
  68. workstream/test/test_llm.py +78 -0
  69. workstream/test/test_markdown.py +626 -0
  70. workstream/test/test_models.py +506 -0
  71. workstream/test/test_next.py +206 -0
  72. workstream/test/test_plan_index.py +83 -0
  73. workstream/test/test_provisioning.py +270 -0
  74. workstream/test/test_repo_discovery.py +181 -0
  75. workstream/test/test_resume.py +71 -0
  76. workstream/test/test_sweep.py +1196 -0
  77. workstream/test/test_sweep_state.py +86 -0
  78. workstream/test/test_thoughts.py +516 -0
  79. workstream/test/test_web.py +606 -0
  80. workstream/thoughts.py +505 -0
  81. workstream/web.py +444 -0
  82. workstream_cli-0.0.1.dist-info/LICENSE +21 -0
  83. workstream_cli-0.0.1.dist-info/METADATA +93 -0
  84. workstream_cli-0.0.1.dist-info/RECORD +86 -0
  85. workstream_cli-0.0.1.dist-info/WHEEL +4 -0
  86. workstream_cli-0.0.1.dist-info/entry_points.txt +3 -0
@@ -0,0 +1,382 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1">
6
+ <title>Workstreams Dashboard</title>
7
+ <style>
8
+ :root {
9
+ --bg: #1a1a2e;
10
+ --surface: #16213e;
11
+ --surface2: #0f3460;
12
+ --text: #e0e0e0;
13
+ --text-muted: #8892a4;
14
+ --accent: #e94560;
15
+ --green: #4ecca3;
16
+ --yellow: #f0c040;
17
+ --blue: #5dadec;
18
+ --purple: #b08cff;
19
+ --orange: #f39c12;
20
+ --border: #2a2a4a;
21
+ }
22
+ * { box-sizing: border-box; margin: 0; padding: 0; }
23
+ body {
24
+ font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
25
+ background: var(--bg);
26
+ color: var(--text);
27
+ line-height: 1.6;
28
+ padding: 2rem;
29
+ }
30
+ a { color: var(--blue); }
31
+ a:visited { color: var(--purple); }
32
+ a:hover { color: var(--accent); }
33
+ h1 {
34
+ font-size: 1.8rem;
35
+ font-weight: 700;
36
+ margin-bottom: 0.25rem;
37
+ }
38
+ .subtitle {
39
+ color: var(--text-muted);
40
+ font-size: 0.9rem;
41
+ margin-bottom: 2rem;
42
+ }
43
+ .stats {
44
+ display: flex;
45
+ gap: 1rem;
46
+ margin-bottom: 2rem;
47
+ flex-wrap: wrap;
48
+ }
49
+ .stat-card {
50
+ background: var(--surface);
51
+ border: 1px solid var(--border);
52
+ border-radius: 8px;
53
+ padding: 1rem 1.5rem;
54
+ min-width: 140px;
55
+ }
56
+ .stat-card .number {
57
+ font-size: 2rem;
58
+ font-weight: 700;
59
+ line-height: 1;
60
+ }
61
+ .stat-card .label {
62
+ font-size: 0.8rem;
63
+ color: var(--text-muted);
64
+ text-transform: uppercase;
65
+ letter-spacing: 0.05em;
66
+ }
67
+ .stat-card.active .number { color: var(--green); }
68
+ .stat-card.snoozed .number { color: var(--yellow); }
69
+ .stat-card.completed .number { color: var(--purple); }
70
+ .stat-card.total .number { color: var(--text); }
71
+
72
+ .section-title {
73
+ font-size: 1.2rem;
74
+ font-weight: 600;
75
+ margin: 2rem 0 1rem;
76
+ padding-bottom: 0.5rem;
77
+ border-bottom: 1px solid var(--border);
78
+ }
79
+
80
+ .ws-grid {
81
+ display: grid;
82
+ grid-template-columns: repeat(auto-fill, minmax(360px, 1fr));
83
+ gap: 1rem;
84
+ }
85
+ .ws-card {
86
+ background: var(--surface);
87
+ border: 1px solid var(--border);
88
+ border-radius: 8px;
89
+ padding: 1.25rem;
90
+ border-left: 3px solid var(--green);
91
+ transition: border-color 0.15s;
92
+ }
93
+ .ws-card:hover {
94
+ border-color: var(--accent);
95
+ }
96
+ .ws-card .ws-header {
97
+ display: flex;
98
+ justify-content: space-between;
99
+ align-items: flex-start;
100
+ margin-bottom: 0.75rem;
101
+ }
102
+ .ws-card .ws-title {
103
+ font-size: 1.05rem;
104
+ font-weight: 600;
105
+ text-decoration: none;
106
+ color: var(--text);
107
+ }
108
+ .ws-card .ws-title:hover { color: var(--accent); }
109
+ .ws-card .ws-meta {
110
+ display: flex;
111
+ gap: 0.5rem;
112
+ flex-wrap: wrap;
113
+ }
114
+ .badge {
115
+ display: inline-block;
116
+ font-size: 0.7rem;
117
+ padding: 0.15rem 0.5rem;
118
+ border-radius: 4px;
119
+ font-weight: 600;
120
+ text-transform: uppercase;
121
+ letter-spacing: 0.03em;
122
+ }
123
+ .badge-active { background: var(--green); color: #000; }
124
+ .badge-snoozed { background: var(--yellow); color: #000; }
125
+ .badge-completed { background: var(--purple); color: #000; }
126
+ .badge-dropped { background: var(--text-muted); color: #000; }
127
+ .badge-size {
128
+ background: var(--surface2);
129
+ color: var(--text-muted);
130
+ border: 1px solid var(--border);
131
+ }
132
+ .tag {
133
+ display: inline-block;
134
+ font-size: 0.7rem;
135
+ color: var(--accent);
136
+ margin-right: 0.25rem;
137
+ text-decoration: none;
138
+ }
139
+ .tag:hover { text-decoration: underline; }
140
+ .tag:visited { color: var(--accent); }
141
+ .ws-card .ws-thread {
142
+ font-size: 0.85rem;
143
+ color: var(--text-muted);
144
+ margin-top: 0.5rem;
145
+ border-left: 2px solid var(--border);
146
+ padding-left: 0.75rem;
147
+ }
148
+ .ws-card .ws-thread .thread-date {
149
+ color: var(--text);
150
+ font-weight: 500;
151
+ font-size: 0.8rem;
152
+ }
153
+ .ws-card .tabled-note {
154
+ font-size: 0.85rem;
155
+ color: var(--yellow);
156
+ margin-top: 0.5rem;
157
+ font-style: italic;
158
+ }
159
+ .ws-card .ws-idle {
160
+ font-size: 0.75rem;
161
+ color: var(--text-muted);
162
+ margin-top: 0.5rem;
163
+ }
164
+ .ws-card .ws-idle.idle-warn { color: var(--yellow); }
165
+ .ws-card .ws-idle.idle-stale { color: var(--accent); }
166
+ .ws-card.idle-warn { border-left-color: var(--yellow); }
167
+ .ws-card.idle-stale { border-left-color: var(--accent); }
168
+ .ws-date {
169
+ font-size: 0.75rem;
170
+ color: var(--text-muted);
171
+ font-weight: 400;
172
+ }
173
+ .ws-card .ws-next {
174
+ margin-top: 0.75rem;
175
+ font-size: 0.85rem;
176
+ }
177
+ .ws-card .ws-next ul {
178
+ list-style: none;
179
+ padding: 0;
180
+ }
181
+ .ws-card .ws-next li::before {
182
+ content: "\2192 ";
183
+ color: var(--accent);
184
+ }
185
+ .ws-card .ws-plans {
186
+ margin-top: 0.5rem;
187
+ font-size: 0.8rem;
188
+ color: var(--text-muted);
189
+ }
190
+ .ws-card .ws-plans span:not(.badge) {
191
+ color: var(--blue);
192
+ }
193
+ .ws-card .ws-branches {
194
+ margin-top: 0.25rem;
195
+ font-size: 0.8rem;
196
+ color: var(--text-muted);
197
+ }
198
+ .ws-card .ws-branches span {
199
+ color: var(--green);
200
+ }
201
+ .ws-card .ws-ideas {
202
+ margin-top: 0.25rem;
203
+ font-size: 0.8rem;
204
+ color: var(--text-muted);
205
+ }
206
+ .ws-card .ws-ideas span {
207
+ color: var(--blue);
208
+ }
209
+ .ws-card .ws-log {
210
+ margin-top: 0.25rem;
211
+ font-size: 0.8rem;
212
+ color: var(--text-muted);
213
+ }
214
+ .ws-card .ws-log span {
215
+ color: var(--purple);
216
+ }
217
+ .ws-parent {
218
+ margin-bottom: 0.5rem;
219
+ }
220
+ .parent-badge {
221
+ font-size: 0.75rem;
222
+ color: var(--orange);
223
+ }
224
+ .ws-children {
225
+ margin-top: 0.75rem;
226
+ border-top: 1px solid var(--border);
227
+ padding-top: 0.5rem;
228
+ }
229
+ .ws-child-row {
230
+ display: flex;
231
+ align-items: center;
232
+ gap: 0.5rem;
233
+ padding: 0.3rem 0;
234
+ font-size: 0.85rem;
235
+ }
236
+ .ws-child-row a {
237
+ color: var(--text);
238
+ text-decoration: none;
239
+ font-weight: 500;
240
+ }
241
+ .ws-child-row a:hover { color: var(--accent); }
242
+ .ws-child-row .badge { font-size: 0.6rem; }
243
+ .ws-child-row .ws-idle { margin: 0; font-size: 0.7rem; }
244
+ .tag-filter-banner {
245
+ background: var(--surface);
246
+ border: 1px solid var(--accent);
247
+ border-radius: 8px;
248
+ padding: 0.75rem 1.25rem;
249
+ margin-bottom: 1.5rem;
250
+ display: flex;
251
+ justify-content: space-between;
252
+ align-items: center;
253
+ font-size: 0.9rem;
254
+ }
255
+ .tag-filter-banner a {
256
+ color: var(--accent);
257
+ text-decoration: none;
258
+ font-weight: 600;
259
+ }
260
+ .tag-filter-banner a:hover { text-decoration: underline; }
261
+ footer {
262
+ margin-top: 3rem;
263
+ padding-top: 1rem;
264
+ border-top: 1px solid var(--border);
265
+ font-size: 0.8rem;
266
+ color: var(--text-muted);
267
+ }
268
+ .ws-plan-row { display: flex; gap: 0.5rem; align-items: baseline; font-size: 0.8rem; margin-top: 0.2rem; }
269
+ .badge-plan-active { background: var(--blue); color: #000; }
270
+ .badge-plan-draft { background: var(--surface2); color: var(--text-muted); border: 1px solid var(--border); }
271
+ .badge-plan-tabled { background: var(--yellow); color: #000; }
272
+ .plan-title { color: var(--text); font-weight: 500; }
273
+ .plan-path { color: var(--text-muted); font-size: 0.75rem; }
274
+ .ws-plans-done { font-size: 0.75rem; color: var(--text-muted); margin-top: 0.25rem; }
275
+ .ws-plans-done span { color: var(--purple); }
276
+ </style>
277
+ </head>
278
+ <body>
279
+ <h1>Workstreams</h1>
280
+ <p class="subtitle">Generated {generated_at} &mdash; {total_count} workstreams</p>
281
+
282
+ <div class="stats">
283
+ <div class="stat-card active">
284
+ <div class="number">{active_count}</div>
285
+ <div class="label">Active</div>
286
+ </div>
287
+ <div class="stat-card snoozed">
288
+ <div class="number">{snoozed_count}</div>
289
+ <div class="label">Snoozed</div>
290
+ </div>
291
+ <div class="stat-card completed">
292
+ <div class="number">{completed_count}</div>
293
+ <div class="label">Completed</div>
294
+ </div>
295
+ </div>
296
+
297
+ {?active_tag}
298
+ <div class="tag-filter-banner">
299
+ <span>Showing: <strong>#{active_tag}</strong></span>
300
+ <a href="/">✕ Clear filter</a>
301
+ </div>
302
+ {/active_tag}
303
+
304
+ {#status_groups}
305
+ <h2 class="section-title">{status_label} ({count})</h2>
306
+ <div class="ws-grid">
307
+ {#workstreams}
308
+ <div class="ws-card {idle_class}">
309
+ <div class="ws-header">
310
+ <a class="ws-title" href="/ws/{id}/">{title}</a>
311
+ <div class="ws-meta">
312
+ {?last_activity}<span class="ws-date" title="{last_activity_iso}">{last_activity_display}</span>{/last_activity}
313
+ <span class="badge badge-{status}">{status}</span>
314
+ <span class="badge badge-size">{size}</span>
315
+ </div>
316
+ </div>
317
+ {?parent}<div class="ws-parent"><span class="parent-badge">&uarr; {?parent_title}{parent_title}{:else}{parent}{/parent_title}</span></div>{/parent}
318
+ {?tags}
319
+ <div>{#tags}<a class="tag" href="/tag/{.}/">#{.}</a>{/tags}</div>
320
+ {/tags}
321
+ {?last_thread_date}
322
+ <div class="ws-thread">
323
+ <span class="thread-date" title="{last_thread_iso}">{last_thread_date}</span> &mdash; {last_thread_body}
324
+ </div>
325
+ {/last_thread_date}
326
+ {?snooze_reason}
327
+ <div class="tabled-note">{snooze_reason}</div>
328
+ {/snooze_reason}
329
+ {?next_actions}
330
+ <div class="ws-next">
331
+ <ul>
332
+ {#next_actions}
333
+ <li>{.}</li>
334
+ {/next_actions}
335
+ </ul>
336
+ </div>
337
+ {/next_actions}
338
+ {?plans}
339
+ <div class="ws-plans">
340
+ {#plans}
341
+ <div class="ws-plan-row">
342
+ <span class="badge badge-plan-{status}">{status}</span>
343
+ {?title}<span class="plan-title">{title}</span>{:else}<span class="plan-path">{path}</span>{/title}
344
+ </div>
345
+ {/plans}
346
+ </div>
347
+ {/plans}
348
+ {?plans_done_text}
349
+ <div class="ws-plans-done"><span>{plans_done_text}</span></div>
350
+ {/plans_done_text}
351
+ {?branches}
352
+ <div class="ws-branches">
353
+ {#branches}<span>{repo}</span>: {branch} (+{ahead}){~s}{/branches}
354
+ </div>
355
+ {/branches}
356
+ {?ideas_count_text}
357
+ <div class="ws-ideas"><span>{ideas_count_text}</span></div>
358
+ {/ideas_count_text}
359
+ {?log_count_text}
360
+ <div class="ws-log"><span>{log_count_text}</span></div>
361
+ {/log_count_text}
362
+ {?children}
363
+ <div class="ws-children">
364
+ {#children}
365
+ <div class="ws-child-row">
366
+ <a href="/ws/{id}/">{title}</a>
367
+ <span class="badge badge-{status}">{status}</span>
368
+ {?idle_text}<span class="ws-idle {idle_class}">{idle_text}</span>{/idle_text}
369
+ </div>
370
+ {/children}
371
+ </div>
372
+ {/children}
373
+ </div>
374
+ {/workstreams}
375
+ </div>
376
+ {/status_groups}
377
+
378
+ <footer>
379
+ Generated by <strong>ws index --html</strong> &mdash; workstream v0.1.0
380
+ </footer>
381
+ </body>
382
+ </html>