@godmode-team/godmode 1.7.2 → 1.8.2

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 (78) hide show
  1. package/LICENSE +94 -46
  2. package/README.md +195 -36
  3. package/assets/agent-roster/competitor-watch.md +40 -0
  4. package/assets/agent-roster/content-writer.md +35 -53
  5. package/assets/agent-roster/godmode-builder.md +2 -2
  6. package/assets/agent-roster/inbox-manager.md +38 -0
  7. package/assets/agent-roster/meeting-prep.md +40 -16
  8. package/assets/agent-roster/skill-optimizer.md +50 -0
  9. package/assets/agent-roster/weekly-review.md +42 -0
  10. package/assets/skills/autoresearch.md +1 -1
  11. package/assets/skills/pattern-scout.md +1 -1
  12. package/assets/skills/visual-qa.md +128 -0
  13. package/dist/godmode-ui/aeo.html +1 -1
  14. package/dist/godmode-ui/assets/brain-tab-B1CYwAJ7.js +402 -0
  15. package/dist/godmode-ui/assets/connections-tab-Cuv4eW0d.js +91 -0
  16. package/dist/godmode-ui/assets/ctrl-settings-COfcdhha.js +5 -0
  17. package/dist/godmode-ui/assets/dashboards-tab-7hHXzWPp.js +137 -0
  18. package/dist/godmode-ui/assets/index-DcYipcbm.js +1994 -0
  19. package/dist/godmode-ui/assets/index-DmEmOd0w.css +1 -0
  20. package/dist/godmode-ui/assets/lit-core-CTInmNPB.js +3 -0
  21. package/dist/godmode-ui/assets/markdown-i_gIkIP3.js +59 -0
  22. package/dist/godmode-ui/assets/second-brain-tab-DkFatLwl.js +350 -0
  23. package/dist/godmode-ui/assets/setup-BnLadXY9.js +1 -0
  24. package/dist/godmode-ui/assets/team-tab-Q3icI_Q-.js +296 -0
  25. package/dist/godmode-ui/assets/today-tab-C6lIMzgY.js +209 -0
  26. package/dist/godmode-ui/assets/views-settings-B2UFEtoi.js +4643 -0
  27. package/dist/godmode-ui/assets/work-tab-DwU559Bx.js +1 -0
  28. package/dist/godmode-ui/assets/workspaces-vzpIVgdl.js +718 -0
  29. package/dist/godmode-ui/index.html +11 -5
  30. package/dist/index.js +1658 -36092
  31. package/dist/mcp-entry.js +1272 -0
  32. package/dist/standalone.js +1917 -0
  33. package/openclaw.plugin.json +36 -7
  34. package/package.json +27 -13
  35. package/scripts/godmode-gateway.service +41 -0
  36. package/scripts/install-systemd.sh +99 -0
  37. package/skill-cards/adversarial-board.md +63 -0
  38. package/skill-cards/autoresearch.md +39 -0
  39. package/skill-cards/bill-review.md +26 -0
  40. package/skill-cards/calendar.md +32 -0
  41. package/skill-cards/code-quality.md +31 -0
  42. package/skill-cards/competitor-scan.md +26 -0
  43. package/skill-cards/content-generation.md +26 -0
  44. package/skill-cards/context-deep-dive.md +65 -0
  45. package/skill-cards/cron-workflows.md +33 -0
  46. package/skill-cards/dashboards.md +38 -0
  47. package/skill-cards/delegate.md +57 -0
  48. package/skill-cards/files.md +38 -0
  49. package/skill-cards/godmode-builder.md +58 -0
  50. package/skill-cards/inbox-sweep.md +26 -0
  51. package/skill-cards/integrations.md +40 -0
  52. package/skill-cards/life-admin.md +26 -0
  53. package/skill-cards/meetings.md +42 -0
  54. package/skill-cards/meta-problem-solver.md +52 -0
  55. package/skill-cards/people.md +39 -0
  56. package/skill-cards/personal-brand.md +71 -0
  57. package/skill-cards/project-orchestrator.md +97 -0
  58. package/skill-cards/project-pipeline.md +78 -0
  59. package/skill-cards/proof-editor.md +28 -0
  60. package/skill-cards/quality-gate.md +57 -0
  61. package/skill-cards/quarterly-review.md +26 -0
  62. package/skill-cards/queue.md +40 -0
  63. package/skill-cards/screenpipe.md +49 -0
  64. package/skill-cards/second-brain.md +46 -0
  65. package/skill-cards/standup-prep.md +26 -0
  66. package/skill-cards/tasks.md +34 -0
  67. package/skill-cards/visual-qa.md +56 -0
  68. package/skill-cards/workspace-memory.md +51 -0
  69. package/skill-cards/x-twitter.md +37 -0
  70. package/dist/godmode-ui/assets/dashboards-CrT3s0NG.js +0 -1
  71. package/dist/godmode-ui/assets/index-BtwTHiwI.js +0 -9353
  72. package/dist/godmode-ui/assets/index-xiAdnGJD.css +0 -1
  73. package/dist/godmode-ui/assets/options-QuHclvvX.js +0 -1
  74. package/dist/godmode-ui/assets/second-brain-ghSM5E6X.js +0 -1
  75. package/dist/godmode-ui/assets/setup-CWjMtnE4.js +0 -1
  76. package/dist/godmode-ui/consciousness-icon-64.png +0 -0
  77. package/dist/godmode-ui/consciousness-icon.png +0 -0
  78. package/dist/godmode-ui/godmode-logo.png +0 -0
@@ -0,0 +1,718 @@
1
+ import{A as c,b as a}from"./lit-core-CTInmNPB.js";import{f as P,ab as Q}from"./ctrl-settings-COfcdhha.js";function ie(e){return!Number.isFinite(e)||e<=0?"0 B":e<1024?`${e} B`:e<1024*1024?`${(e/1024).toFixed(1)} KB`:`${(e/(1024*1024)).toFixed(1)} MB`}function z(e){switch(e){case"markdown":return"📄";case"html":return"🌐";case"image":return"🖼️";case"json":return"🧩";case"folder":return"📁";default:return"📄"}}function te(e){return e==="running"?"ws-session-dot ws-session-dot--running":e==="blocked"?"ws-session-dot ws-session-dot--blocked":"ws-session-dot ws-session-dot--complete"}function le(e){return`ws-task-priority ws-task-priority--${e}`}function oe(e){return e==="high"?"High":e==="low"?"Low":"Med"}function re(e){if(!e)return"";const t=Q();return e===t?"Today":e<t?`Overdue (${e})`:e}function ce(e){if(!e)return"ws-task-due";const t=Q();return e<t?"ws-task-due ws-task-due--overdue":e===t?"ws-task-due ws-task-due--today":"ws-task-due"}function V(e,t="due"){const s={high:0,medium:1,low:2};return[...e].sort((n,i)=>{if(t==="priority"){const l=s[n.priority]-s[i.priority];return l!==0?l:n.dueDate&&i.dueDate?n.dueDate.localeCompare(i.dueDate):n.dueDate&&!i.dueDate?-1:!n.dueDate&&i.dueDate?1:0}if(t==="newest")return(i.createdAt||"").localeCompare(n.createdAt||"");if(n.dueDate&&i.dueDate){const l=n.dueDate.localeCompare(i.dueDate);if(l!==0)return l}else{if(n.dueDate&&!i.dueDate)return-1;if(!n.dueDate&&i.dueDate)return 1}return s[n.priority]-s[i.priority]})}function se(e,t,s,n,i,l,r){const p=e.status==="complete";return n===e.id?a`
2
+ <form
3
+ class="ws-list-row ws-task-row ws-task-edit-row"
4
+ aria-label="Edit task: ${e.title}"
5
+ @submit=${d=>{d.preventDefault();const m=d.currentTarget,u=m.querySelector(".ws-task-edit-input"),k=m.querySelector(".ws-task-date-input"),b=u.value.trim();b&&(l?.(e.id,{title:b,dueDate:k.value||null}),i?.(null))}}
6
+ >
7
+ <input
8
+ type="text"
9
+ class="ws-task-edit-input"
10
+ aria-label="Task title"
11
+ .value=${e.title}
12
+ @click=${d=>d.stopPropagation()}
13
+ />
14
+ <input
15
+ type="date"
16
+ class="ws-task-date-input"
17
+ aria-label="Task due date"
18
+ .value=${e.dueDate??""}
19
+ />
20
+ <button type="submit" class="ws-task-save-btn" aria-label="Save task changes">Save</button>
21
+ <button
22
+ type="button"
23
+ class="ws-task-cancel-btn"
24
+ aria-label="Cancel editing"
25
+ @click=${()=>i?.(null)}
26
+ >Cancel</button>
27
+ </form>
28
+ `:a`
29
+ <div class="ws-list-row ws-task-row ${p?"ws-task-row--complete":""}" role="listitem">
30
+ <button
31
+ class="ws-task-check ${p?"ws-task-check--done":""}"
32
+ @click=${()=>t?.(e.id,e.status)}
33
+ title=${p?"Mark incomplete":"Mark complete"}
34
+ aria-label="${p?"Mark incomplete":"Mark complete"}: ${e.title}"
35
+ >
36
+ ${p?"✓":""}
37
+ </button>
38
+ <span
39
+ class="ws-list-title ws-task-title-clickable ${p?"ws-task-title--done":""}"
40
+ @click=${()=>i?.(e.id)}
41
+ title="Click to edit"
42
+ >${e.title}</span>
43
+ ${e.briefSection?a`<span class="ws-task-section">${e.briefSection}</span>`:c}
44
+ <span class=${le(e.priority)}>${oe(e.priority)}</span>
45
+ ${e.dueDate?a`<span class=${ce(e.dueDate)}>${re(e.dueDate)}</span>`:c}
46
+ ${!p&&e.queueStatus?.status==="processing"?a`<span class="ws-task-agent-status ws-task-agent-status--processing" aria-live="polite">
47
+ <span class="ws-task-agent-dot"></span>
48
+ ${e.queueStatus.roleName} working...
49
+ </span>`:!p&&e.queueStatus?.status==="review"&&s?a`<button
50
+ class="ws-task-start-btn ws-task-start-btn--review"
51
+ @click=${()=>s(e.id)}
52
+ title="Review agent output"
53
+ aria-label="Review agent output for: ${e.title}"
54
+ >Review</button>`:e.queueStatus?.status==="done"?a`
55
+ ${r?a`<button
56
+ class="ws-task-start-btn ws-task-start-btn--done"
57
+ @click=${()=>r(e.id)}
58
+ title="Preview agent output"
59
+ aria-label="View output for: ${e.title}"
60
+ >View Output</button>`:c}
61
+ ${s?a`<button
62
+ class="ws-task-start-btn ws-task-start-btn--chat"
63
+ @click=${()=>s(e.id)}
64
+ title="Open chat session for this task"
65
+ aria-label="Open chat for: ${e.title}"
66
+ >Open Chat</button>`:c}
67
+ `:!p&&s?a`<button
68
+ class="ws-task-start-btn"
69
+ @click=${()=>s(e.id)}
70
+ title="Start working on this task"
71
+ aria-label="Start task: ${e.title}"
72
+ >Start</button>`:c}
73
+ </div>
74
+ `}function $e(e,t,s,n,i,l,r){const p=e.status==="complete";return n===e.id?a`
75
+ <form
76
+ class="ws-list-row ws-task-row ws-task-edit-row"
77
+ aria-label="Edit task: ${e.title}"
78
+ @submit=${d=>{d.preventDefault();const m=d.currentTarget,u=m.querySelector(".ws-task-edit-input"),k=m.querySelector(".ws-task-date-input"),b=u.value.trim();b&&(l?.(e.id,{title:b,dueDate:k.value||null}),i?.(null))}}
79
+ >
80
+ <input
81
+ type="text"
82
+ class="ws-task-edit-input"
83
+ aria-label="Task title"
84
+ .value=${e.title}
85
+ @click=${d=>d.stopPropagation()}
86
+ />
87
+ <input
88
+ type="date"
89
+ class="ws-task-date-input"
90
+ aria-label="Task due date"
91
+ .value=${e.dueDate??""}
92
+ />
93
+ <button type="submit" class="ws-task-save-btn" aria-label="Save task changes">Save</button>
94
+ <button
95
+ type="button"
96
+ class="ws-task-cancel-btn"
97
+ aria-label="Cancel editing"
98
+ @click=${()=>i?.(null)}
99
+ >Cancel</button>
100
+ </form>
101
+ `:a`
102
+ <div class="ws-list-row ws-task-row ${p?"ws-task-row--complete":""}" role="listitem">
103
+ <button
104
+ class="ws-task-check ${p?"ws-task-check--done":""}"
105
+ @click=${()=>t?.(e.id,e.status)}
106
+ title=${p?"Mark incomplete":"Mark complete"}
107
+ aria-label="${p?"Mark incomplete":"Mark complete"}: ${e.title}"
108
+ >
109
+ ${p?"✓":""}
110
+ </button>
111
+ <span
112
+ class="ws-list-title ws-task-title-clickable ${p?"ws-task-title--done":""}"
113
+ @click=${()=>i?.(e.id)}
114
+ title="Click to edit"
115
+ >${e.title}</span>
116
+ ${e.project?a`<span class="ws-task-project">${e.project}</span>`:c}
117
+ ${e.briefSection?a`<span class="ws-task-section">${e.briefSection}</span>`:c}
118
+ <span class=${le(e.priority)}>${oe(e.priority)}</span>
119
+ ${e.dueDate?a`<span class=${ce(e.dueDate)}>${re(e.dueDate)}</span>`:c}
120
+ ${!p&&e.queueStatus?.status==="processing"?a`<span class="ws-task-agent-status ws-task-agent-status--processing" aria-live="polite">
121
+ <span class="ws-task-agent-dot"></span>
122
+ ${e.queueStatus.roleName} working...
123
+ </span>`:!p&&e.queueStatus?.status==="review"&&s?a`<button
124
+ class="ws-task-start-btn ws-task-start-btn--review"
125
+ @click=${()=>s(e.id)}
126
+ title="Review agent output"
127
+ aria-label="Review agent output for: ${e.title}"
128
+ >Review</button>`:e.queueStatus?.status==="done"?a`
129
+ ${r?a`<button
130
+ class="ws-task-start-btn ws-task-start-btn--done"
131
+ @click=${()=>r(e.id)}
132
+ title="Preview agent output"
133
+ aria-label="View output for: ${e.title}"
134
+ >View Output</button>`:c}
135
+ ${s?a`<button
136
+ class="ws-task-start-btn ws-task-start-btn--chat"
137
+ @click=${()=>s(e.id)}
138
+ title="Open chat session for this task"
139
+ aria-label="Open chat for: ${e.title}"
140
+ >Open Chat</button>`:c}
141
+ `:!p&&s?a`<button
142
+ class="ws-task-start-btn"
143
+ @click=${()=>s(e.id)}
144
+ title="Start working on this task"
145
+ aria-label="Start task: ${e.title}"
146
+ >Start</button>`:c}
147
+ </div>
148
+ `}function be(e,t){return e.trim()?t.toLowerCase().includes(e.trim().toLowerCase()):!0}function ae(e,t){if(!e.trim())return t;const s=e.trim().toLowerCase();return t.filter(n=>n.name.toLowerCase().includes(s)||n.path.toLowerCase().includes(s)||n.type.toLowerCase().includes(s)||(n.searchText??"").toLowerCase().includes(s))}function ne(e,t){if(!e.trim())return t;const s=e.trim().toLowerCase();return t.filter(n=>n.title.toLowerCase().includes(s)||n.key.toLowerCase().includes(s))}function pe(e,t){if(!e.trim())return t;const s=e.trim().toLowerCase();return t.reduce((n,i)=>{if(i.type==="file")(i.name.toLowerCase().includes(s)||i.path.toLowerCase().includes(s))&&n.push(i);else{const l=pe(e,i.children??[]);l.length>0&&n.push({...i,children:l})}return n},[])}function de(e){let t=0;for(const s of e)s.type==="file"?t++:s.children&&(t+=de(s.children));return t}const ke=10;function fe(e){if(!e.searchText)return null;const t=e.searchText.trim();if(!t)return null;const s=t.match(/#+ (.+?)(?:\s#|$)/);return s?s[1].trim().slice(0,120):(t.startsWith("---")?t.replace(/^---.*?---\s*/s,""):t).slice(0,120)||null}function he(e,t=ke){return[...e].sort((s,n)=>n.modified.getTime()-s.modified.getTime()).slice(0,t)}function ue(e,t,s){if(e.type==="file"){const r=s.pinnedPaths.has(e.path);return a`
149
+ <div class="ws-folder-file-row" role="listitem" style="padding-left: ${12+t*16}px">
150
+ <button
151
+ class="ws-folder-file"
152
+ aria-label="Open file: ${e.name}"
153
+ @click=${()=>s.onItemClick?.({path:e.path,name:e.name,type:e.fileType??"text",size:e.size??0,modified:e.modified??new Date})}
154
+ >
155
+ <span class="ws-list-icon" aria-hidden="true">${z(e.fileType??"text")}</span>
156
+ <span class="ws-list-title">${e.name}</span>
157
+ ${e.size!=null?a`<span class="ws-list-meta">${ie(e.size)}</span>`:c}
158
+ ${e.modified?a`<span class="ws-list-meta">${P(e.modified.getTime())}</span>`:c}
159
+ </button>
160
+ <button
161
+ class="ws-pin-btn ${r?"active":""}"
162
+ @click=${()=>s.onPinToggle?.(s.workspaceId,e.path,r)}
163
+ title=${r?"Unpin":"Pin"}
164
+ aria-label="${r?"Unpin":"Pin"} file: ${e.name}"
165
+ >
166
+ ${r?"Unpin":"Pin"}
167
+ </button>
168
+ </div>
169
+ `}const n=s.expandedFolders.has(e.path),i=e.children??[],l=de(i);return a`
170
+ <div class="ws-folder-node" role="listitem">
171
+ <button
172
+ class="ws-folder-header"
173
+ style="padding-left: ${12+t*16}px"
174
+ @click=${()=>s.onToggleFolder?.(e.path)}
175
+ aria-expanded=${n}
176
+ aria-label="${n?"Collapse":"Expand"} folder: ${e.name}, ${l} files"
177
+ >
178
+ <span class="ws-folder-chevron ${n?"expanded":""}" aria-hidden="true">&#9654;</span>
179
+ <span class="ws-list-icon" aria-hidden="true">&#128193;</span>
180
+ <span class="ws-folder-name">${e.name}</span>
181
+ <span class="ws-folder-count">${l} ${l===1?"file":"files"}</span>
182
+ </button>
183
+ ${n?a`
184
+ <div class="ws-folder-children">
185
+ ${i.map(r=>ue(r,t+1,s))}
186
+ </div>
187
+ `:c}
188
+ </div>
189
+ `}function ve(e,t,s){return a`
190
+ <div class="workspace-card-wrapper" role="listitem">
191
+ <button
192
+ class="workspace-card"
193
+ @click=${()=>{console.log("[workspace-card] click:",e.name,"onSelect:",typeof t),t?.(e)}}
194
+ title="Open workspace"
195
+ aria-label="Open workspace: ${e.name}"
196
+ >
197
+ <div class="workspace-card-emoji" aria-hidden="true">${e.emoji}</div>
198
+ <div class="workspace-card-content">
199
+ <div class="workspace-card-name">${e.name}</div>
200
+ <div class="workspace-card-meta">
201
+ ${e.connectionCount>0?a`<span>${e.connectionCount} connections</span><span class="workspace-card-separator">•</span>`:c}
202
+ <span>${e.artifactCount} artifacts</span>
203
+ <span class="workspace-card-separator">•</span>
204
+ <span>${e.sessionCount} sessions</span>
205
+ ${e.feedCount>0?a`<span class="workspace-card-separator">•</span><span>${e.feedCount} feed</span>`:c}
206
+ <span class="workspace-card-separator">•</span>
207
+ <span>${P(e.lastUpdated.getTime())}</span>
208
+ </div>
209
+ </div>
210
+ </button>
211
+ ${s?a`<button
212
+ class="workspace-card-delete"
213
+ title="Delete workspace"
214
+ aria-label="Delete workspace: ${e.name}"
215
+ @click=${n=>{n.stopPropagation(),confirm(`Delete workspace "${e.name}"? This removes it from your list but does not delete any files.`)&&s(e)}}
216
+ >&times;</button>`:c}
217
+ </div>
218
+ `}function j(e){const{workspaceId:t,entry:s,pinned:n,onOpen:i,onPinToggle:l}=e;return a`
219
+ <div class="ws-list-row" role="listitem">
220
+ <button class="ws-list-main" @click=${()=>i?.(s)} aria-label="Open file: ${s.name}">
221
+ <span class="ws-list-icon" aria-hidden="true">${z(s.type)}</span>
222
+ <span class="ws-list-title">${s.name}</span>
223
+ <span class="ws-list-meta">${ie(s.size)}</span>
224
+ <span class="ws-list-meta">${P(s.modified.getTime())}</span>
225
+ </button>
226
+ <button
227
+ class="ws-pin-btn ${n?"active":""}"
228
+ @click=${()=>l?.(t,s.path,n)}
229
+ title=${n?"Unpin":"Pin"}
230
+ aria-label="${n?"Unpin":"Pin"} file: ${s.name}"
231
+ >
232
+ ${n?"Unpin":"Pin"}
233
+ </button>
234
+ </div>
235
+ `}function ge(e){const{workspaceId:t,entry:s,pinned:n,onOpen:i,onPinToggle:l}=e,r=fe(s);return a`
236
+ <div class="ws-list-row" role="listitem">
237
+ <button class="ws-list-main" @click=${()=>i?.(s)} aria-label="Open file: ${s.name}">
238
+ <span class="ws-list-icon" aria-hidden="true">${z(s.type)}</span>
239
+ <span class="ws-list-title">${s.name}</span>
240
+ <span class="ws-list-meta">${P(s.modified.getTime())}</span>
241
+ ${r?a`<span class="ws-list-desc">${r}</span>`:c}
242
+ </button>
243
+ <button
244
+ class="ws-pin-btn ${n?"active":""}"
245
+ @click=${()=>l?.(t,s.path,n)}
246
+ title=${n?"Unpin":"Pin"}
247
+ aria-label="${n?"Unpin":"Pin"} file: ${s.name}"
248
+ >
249
+ ${n?"Unpin":"Pin"}
250
+ </button>
251
+ </div>
252
+ `}function ye(e,t){return a`
253
+ <nav class="workspace-breadcrumbs" aria-label="File browser breadcrumb">
254
+ ${e.map((s,n)=>a`
255
+ ${n>0?a`<span class="breadcrumb-sep" aria-hidden="true">/</span>`:c}
256
+ <button
257
+ class="breadcrumb-item ${n===e.length-1?"breadcrumb-current":""}"
258
+ @click=${()=>t(s.path)}
259
+ aria-current=${n===e.length-1?"location":c}
260
+ >${s.name}</button>
261
+ `)}
262
+ </nav>
263
+ `}function Te(e){const{browseEntries:t,breadcrumbs:s,browseSearchQuery:n,browseSearchResults:i,onBrowseFolder:l,onBrowseSearch:r,onBrowseBack:p,onCreateFolder:$,onItemClick:d}=e,m=i??t??[];return a`
264
+ <div class="workspace-browser" role="region" aria-label="File browser">
265
+ <div class="workspace-browser-toolbar">
266
+ <button class="workspace-browse-back" @click=${()=>p?.()} aria-label="Go back to workspace">
267
+ &larr; Back
268
+ </button>
269
+ ${s?ye(s,u=>l?.(u)):c}
270
+ <input
271
+ type="text"
272
+ class="workspace-browse-search"
273
+ placeholder="Search files..."
274
+ aria-label="Search files in workspace"
275
+ .value=${n??""}
276
+ @input=${u=>{const k=u.target;r?.(k.value)}}
277
+ />
278
+ <button
279
+ class="workspace-browse-new-folder"
280
+ aria-label="Create new folder"
281
+ @click=${()=>{const u=prompt("New folder name:");if(u?.trim()){const k=s?.[s.length-1]?.path??".";$?.(`${k}/${u.trim()}`)}}}
282
+ >+ Folder</button>
283
+ </div>
284
+
285
+ <div class="workspace-browse-list" role="list" aria-label="File listing">
286
+ ${m.length===0?a`<div class="workspace-browse-empty">No files found</div>`:m.map(u=>a`
287
+ <button
288
+ class="workspace-browse-entry"
289
+ @click=${()=>{u.type==="folder"?l?.(u.path):d&&d({path:u.path,name:u.name,type:u.fileType??"text",size:u.size??0,modified:new Date})}}
290
+ >
291
+ <span class="browse-entry-icon">${u.type==="folder"?"📁":"📄"}</span>
292
+ <span class="browse-entry-name">${u.name}</span>
293
+ ${u.excerpt?a`<span class="browse-entry-excerpt">${u.excerpt}</span>`:c}
294
+ </button>
295
+ `)}
296
+ </div>
297
+ </div>
298
+ `}function Se(e){const{workspace:t,itemSearchQuery:s,expandedFolders:n=new Set,showCompletedTasks:i=!1,onItemSearch:l,onBack:r,onItemClick:p,onSessionClick:$,onPinToggle:d,onPinSessionToggle:m,onToggleFolder:u,onToggleTaskComplete:k,onCreateTask:b,onToggleCompletedTasks:f,onStartTask:D,editingTaskId:h,onEditTask:T,onUpdateTask:w,onBatchPushToDrive:v}=e,S=ae(s,t.pinned).toSorted((o,C)=>C.modified.getTime()-o.modified.getTime()),F=ne(s,t.pinnedSessions),g=ae(s,t.outputs).filter(o=>!t.pinned.some(C=>C.path===o.path)),x=(t.folderTree?.length??0)>0,L=x?pe(s,t.folderTree):[],O=ne(s,t.sessions),B=new Set(t.pinnedSessions.map(o=>o.key)),R=new Set(t.pinned.map(o=>o.path)),A=s.trim().length>0,_=S.length>0||F.length>0,N=O.length>0||t.sessions.length===0||A,I=he(t.outputs),W=I.length>0&&!A,M={expandedFolders:n,pinnedPaths:R,workspaceId:t.id,onToggleFolder:u,onItemClick:p,onPinToggle:d};return a`
299
+ <div class="workspaces-container" role="region" aria-label="Workspace: ${t.name}">
300
+ <div class="workspaces-header">
301
+ <div class="workspaces-title">
302
+ <button class="workspace-back-btn" @click=${r} aria-label="Back to workspace list">&#8592;</button>
303
+ <span class="workspaces-icon" aria-hidden="true">${t.emoji}</span>
304
+ <div class="workspace-header-text">
305
+ <span class="workspace-header-name">${t.name}</span>
306
+ <span class="workspace-header-desc">${t.path}</span>
307
+ </div>
308
+ </div>
309
+ <div class="workspace-detail-search">
310
+ <input
311
+ type="text"
312
+ class="workspaces-search-input"
313
+ placeholder="Search workspace..."
314
+ aria-label="Search within ${t.name}"
315
+ .value=${s}
316
+ @input=${o=>l?.(o.target.value)}
317
+ />
318
+ <button
319
+ class="workspace-browse-btn"
320
+ aria-label="Browse files in ${t.name}"
321
+ @click=${()=>e.onBrowseFolder?.(".")}
322
+ >Browse Files</button>
323
+ </div>
324
+ </div>
325
+
326
+ <div class="workspace-content">
327
+ ${e.browsePath!=null?Te(e):c}
328
+
329
+ ${_?a`
330
+ <section class="ws-section" aria-label="Pinned items">
331
+ <div class="ws-section__header">
332
+ <h3>Pinned</h3>
333
+ <span>${S.length+F.length}</span>
334
+ </div>
335
+ <div class="ws-list" role="list" aria-label="Pinned items list">
336
+ ${F.map(o=>a`
337
+ <div class="ws-list-row" role="listitem">
338
+ <button class="ws-list-main" @click=${()=>$?.(o)} aria-label="Open session: ${o.title}">
339
+ <span class=${te(o.status)} aria-label="Status: ${o.status}"></span>
340
+ <span class="ws-list-title">${o.title}</span>
341
+ <span class="ws-list-meta">${P(o.created.getTime())}</span>
342
+ </button>
343
+ <button
344
+ class="ws-pin-btn active"
345
+ @click=${()=>m?.(t.id,o.key,!0)}
346
+ title="Unpin"
347
+ aria-label="Unpin session: ${o.title}"
348
+ >
349
+ Unpin
350
+ </button>
351
+ </div>
352
+ `)}
353
+ ${S.map(o=>j({workspaceId:t.id,entry:o,pinned:!0,onOpen:p,onPinToggle:d}))}
354
+ </div>
355
+ </section>
356
+ `:c}
357
+
358
+ ${Fe({tasks:t.tasks??[],workspaceName:t.name,showCompleted:i,onToggleTaskComplete:k,onCreateTask:b,onToggleCompletedTasks:f,onStartTask:D,onViewTaskOutput,editingTaskId:h,onEditTask:T,onUpdateTask:w})}
359
+
360
+ ${W?a`
361
+ <section class="ws-section" aria-label="Recent files">
362
+ <div class="ws-section__header">
363
+ <h3>Recent</h3>
364
+ <span>${I.length}</span>
365
+ </div>
366
+ <div class="ws-list" role="list" aria-label="Recent files list">
367
+ ${I.map(o=>ge({workspaceId:t.id,entry:o,pinned:R.has(o.path),onOpen:p,onPinToggle:d}))}
368
+ </div>
369
+ </section>
370
+ `:c}
371
+
372
+ <section class="ws-section" aria-label="Artifacts">
373
+ <div class="ws-section__header">
374
+ <h3>Artifacts</h3>
375
+ <span>${x?L.length:g.length}</span>
376
+ ${v&&g.length>0?a`<button class="ws-export-drive-btn" aria-label="Export all artifacts to Google Drive" @click=${()=>{const o=g.map(C=>C.path);v(o)}}>Export to Drive</button>`:c}
377
+ </div>
378
+ <div class="ws-list ws-list--scroll" role="list" aria-label="Artifacts list">
379
+ ${x?L.length===0?a`<div class="ws-empty">
380
+ <span class="ws-empty-hint">No artifacts yet. Ask your ally to create a document, plan, or analysis — it'll appear here.</span>
381
+ </div>`:L.map(o=>ue(o,0,M)):g.length===0?a`<div class="ws-empty">
382
+ <span class="ws-empty-hint">No artifacts yet. Ask your ally to create a document, plan, or analysis — it'll appear here.</span>
383
+ </div>`:g.map(o=>j({workspaceId:t.id,entry:o,pinned:!1,onOpen:p,onPinToggle:d}))}
384
+ </div>
385
+ </section>
386
+
387
+ ${N?a`
388
+ <section class="ws-section" aria-label="Sessions">
389
+ <div class="ws-section__header">
390
+ <h3>Sessions</h3>
391
+ <span>${O.length}</span>
392
+ </div>
393
+ <div class="ws-list ws-list--scroll" role="list" aria-label="Sessions list">
394
+ ${O.length===0?a`
395
+ <div class="ws-empty">
396
+ <span class="ws-empty-hint">No sessions yet. Sessions are saved conversations with your ally — start a chat to create one.</span>
397
+ </div>
398
+ `:O.map(o=>a`
399
+ <div class="ws-list-row" role="listitem">
400
+ <button class="ws-list-main ws-list-row--button" @click=${()=>$?.(o)} aria-label="Open session: ${o.title}">
401
+ <span class=${te(o.status)} aria-label="Status: ${o.status}"></span>
402
+ <span class="ws-list-title">${o.title}</span>
403
+ <span class="ws-list-meta">${P(o.created.getTime())}</span>
404
+ </button>
405
+ <button
406
+ class="ws-pin-btn ${B.has(o.key)?"active":""}"
407
+ @click=${()=>m?.(t.id,o.key,B.has(o.key))}
408
+ title=${B.has(o.key)?"Unpin":"Pin"}
409
+ aria-label="${B.has(o.key)?"Unpin":"Pin"} session: ${o.title}"
410
+ >
411
+ ${B.has(o.key)?"Unpin":"Pin"}
412
+ </button>
413
+ </div>
414
+ `)}
415
+ </div>
416
+ </section>
417
+ `:c}
418
+
419
+ ${(t.memory?.length??0)>0?a`
420
+ <section class="ws-section" aria-label="Workspace memory">
421
+ <div class="ws-section__header">
422
+ <h3>Memory</h3>
423
+ <span>${t.memory.length}</span>
424
+ </div>
425
+ <div class="ws-list ws-list--scroll" role="list" aria-label="Memory files list">
426
+ ${t.memory.map(o=>j({workspaceId:t.id,entry:o,pinned:R.has(o.path),onOpen:p,onPinToggle:d}))}
427
+ </div>
428
+ </section>
429
+ `:c}
430
+
431
+ ${Ce({entries:t.feedEntries??[],onPost:e.onPostToFeed,onLoadMore:e.onLoadMoreFeed})}
432
+
433
+ ${Pe({connections:t.connections??[],onTest:e.onTestConnection,onRemove:e.onRemoveConnection})}
434
+
435
+ ${De(t.members??[])}
436
+ </div>
437
+ </div>
438
+ `}function Ce(e){const{entries:t,onPost:s,onLoadMore:n}=e;function i(r){switch(r){case"decision":return"📝";case"request":return"❓";case"artifact":return"📦";case"sop":return"📋";case"alert":return"🚨";default:return"💬"}}function l(r){return r.includes("agent")||r.includes(":agent")?"🤖":r==="system"?"⚙️":"👤"}return a`
439
+ <section class="ws-section" aria-label="Activity feed">
440
+ <div class="ws-section__header">
441
+ <h3>Activity Feed</h3>
442
+ <span>${t.length}</span>
443
+ </div>
444
+ <div class="ws-list ws-list--scroll" role="list" aria-live="polite" aria-label="Feed entries" style="max-height: 400px;">
445
+ ${t.length===0?a`<div class="ws-empty">
446
+ <span class="ws-empty-hint">No activity yet. Post updates, decisions, or requests to the feed.</span>
447
+ </div>`:t.map(r=>a`
448
+ <div class="ws-list-row ws-feed-entry">
449
+ <div class="ws-list-main" style="flex-direction: column; align-items: flex-start; gap: 4px; padding: 8px 12px;">
450
+ <div style="display: flex; align-items: center; gap: 8px; width: 100%;">
451
+ <span>${l(r.author)}</span>
452
+ <span class="ws-list-title" style="font-weight: 500;">${r.author}</span>
453
+ <span style="margin-left: auto;">${i(r.type)}</span>
454
+ <span class="ws-list-meta">${P(new Date(r.ts).getTime())}</span>
455
+ </div>
456
+ <div style="padding-left: 28px; opacity: 0.9; font-size: 0.9em;">${r.text}</div>
457
+ </div>
458
+ </div>
459
+ `)}
460
+ </div>
461
+ ${t.length>=50&&n?a`<button class="ws-task-completed-toggle" aria-label="Load more feed entries" @click=${()=>n()}>Load more...</button>`:c}
462
+ ${s?a`
463
+ <form
464
+ class="ws-task-create-form"
465
+ aria-label="Post to activity feed"
466
+ @submit=${r=>{r.preventDefault();const p=r.currentTarget,$=p.querySelector(".ws-feed-input"),d=p.querySelector(".ws-feed-type"),m=$.value.trim();m&&(s(m,d.value),$.value="")}}
467
+ >
468
+ <input
469
+ type="text"
470
+ class="ws-task-create-input ws-feed-input"
471
+ placeholder="Post to feed..."
472
+ aria-label="Feed post content"
473
+ />
474
+ <select class="ws-task-create-project ws-feed-type" aria-label="Post type">
475
+ <option value="update">Update</option>
476
+ <option value="decision">Decision</option>
477
+ <option value="request">Request</option>
478
+ <option value="sop">SOP</option>
479
+ <option value="artifact">Artifact</option>
480
+ </select>
481
+ <button type="submit" class="ws-task-create-btn" aria-label="Submit post">Post</button>
482
+ </form>
483
+ `:c}
484
+ </section>
485
+ `}function Pe(e){const{connections:t,onTest:s,onRemove:n}=e;function i(l){return l==="connected"?a`<span class="ws-conn-status ws-conn-status--ok">Connected</span>`:l==="error"?a`<span class="ws-conn-status ws-conn-status--error">Error</span>`:a`<span class="ws-conn-status ws-conn-status--unconfigured">Not configured</span>`}return t.length===0?a`
486
+ <section class="ws-section" aria-label="Connections">
487
+ <div class="ws-section__header">
488
+ <h3>Connections</h3>
489
+ <span>0</span>
490
+ </div>
491
+ <div class="ws-empty">
492
+ <span class="ws-empty-hint">No tools connected. Connect Google Drive, ClickUp, HubSpot, or other shared tools via Settings.</span>
493
+ </div>
494
+ </section>
495
+ `:a`
496
+ <section class="ws-section" aria-label="Connections">
497
+ <div class="ws-section__header">
498
+ <h3>Connections</h3>
499
+ <span>${t.length}</span>
500
+ </div>
501
+ <div class="ws-list" role="list" aria-label="Connection list">
502
+ ${t.map(l=>a`
503
+ <div class="ws-list-row" role="listitem">
504
+ <div class="ws-list-main" style="gap: 8px;">
505
+ <span class="ws-list-title">${l.name}</span>
506
+ ${i(l.status)}
507
+ ${l.lastSync?a`<span class="ws-list-meta">Synced ${P(new Date(l.lastSync).getTime())}</span>`:c}
508
+ ${l.error?a`<span class="ws-list-meta" style="color: var(--danger-color, #e74c3c);">${l.error}</span>`:c}
509
+ </div>
510
+ <div style="display: flex; gap: 4px;">
511
+ ${s?a`<button class="ws-pin-btn" @click=${()=>s(l.id)} title="Test connection" aria-label="Test connection: ${l.name}">Test</button>`:c}
512
+ ${n?a`<button class="ws-pin-btn" @click=${()=>{confirm(`Remove connection "${l.name}"?`)&&n(l.id)}} title="Remove connection" aria-label="Remove connection: ${l.name}">Remove</button>`:c}
513
+ </div>
514
+ </div>
515
+ `)}
516
+ </div>
517
+ </section>
518
+ `}function De(e){return e.length===0?a``:a`
519
+ <section class="ws-section" aria-label="Workspace members">
520
+ <div class="ws-section__header">
521
+ <h3>Members</h3>
522
+ <span>${e.length}</span>
523
+ </div>
524
+ <div class="ws-list" role="list" aria-label="Members list">
525
+ ${e.map(t=>a`
526
+ <div class="ws-list-row" role="listitem">
527
+ <div class="ws-list-main">
528
+ <span aria-hidden="true">\u{1F464}</span>
529
+ <span class="ws-list-title">${t.name}</span>
530
+ <span class="ws-list-meta">${t.role}</span>
531
+ </div>
532
+ </div>
533
+ `)}
534
+ </div>
535
+ </section>
536
+ `}function Fe(e){const{tasks:t,workspaceName:s,showCompleted:n,onToggleTaskComplete:i,onCreateTask:l,onToggleCompletedTasks:r,onStartTask:p,onViewTaskOutput:$,editingTaskId:d,onEditTask:m,onUpdateTask:u}=e,k=V(t.filter(f=>f.status==="pending")),b=V(t.filter(f=>f.status==="complete"));return a`
537
+ <section class="ws-section" aria-label="Workspace tasks">
538
+ <div class="ws-section__header">
539
+ <h3>Tasks</h3>
540
+ <span>${k.length} open${b.length>0?`, ${b.length} done`:""}</span>
541
+ </div>
542
+ <div class="ws-list ws-list--scroll" role="list" aria-live="polite" aria-label="Task list">
543
+ ${k.length===0&&b.length===0?a`<div class="ws-empty">No tasks</div>`:c}
544
+ ${k.map(f=>se(f,i,p,d,m,u,$))}
545
+ ${b.length>0?a`
546
+ <button class="ws-task-completed-toggle" aria-expanded=${n} @click=${()=>r?.()}>
547
+ ${n?"Hide":"Show"} ${b.length} completed
548
+ </button>
549
+ ${n?b.map(f=>se(f,i,p,d,m,u,$)):c}
550
+ `:c}
551
+ </div>
552
+ ${l?a`
553
+ <form
554
+ class="ws-task-create-form"
555
+ aria-label="Create new task"
556
+ @submit=${f=>{f.preventDefault();const h=f.currentTarget.querySelector("input"),T=h.value.trim();T&&(l(T,s),h.value="")}}
557
+ >
558
+ <input
559
+ type="text"
560
+ class="ws-task-create-input"
561
+ placeholder="Add a task..."
562
+ aria-label="New task title"
563
+ />
564
+ <button type="submit" class="ws-task-create-btn" aria-label="Add task">Add</button>
565
+ </form>
566
+ `:c}
567
+ </section>
568
+ `}function Re(e){const{connected:t,workspaces:s,selectedWorkspace:n,searchQuery:i,itemSearchQuery:l,expandedFolders:r,loading:p,createLoading:$,error:d,allTasks:m=[],taskFilter:u="outstanding",taskSort:k="due",taskSearch:b="",showCompletedTasks:f=!1,editingTaskId:D,workspaceNames:h=[],onSearch:T,onItemSearch:w,onSelectWorkspace:v,onBack:S,onItemClick:F,onSessionClick:g,onPinToggle:x,onPinSessionToggle:L,onCreateWorkspace:O,onDeleteWorkspace:B,onToggleFolder:R,onTeamSetup:A,onToggleTaskComplete:_,onCreateTask:N,onSetTaskFilter:I,onSetTaskSort:W,onSetTaskSearch:M,onToggleCompletedTasks:o,onStartTask:C,onViewTaskOutput:we,onEditTask:G,onUpdateTask:H}=e,U=s.filter(y=>be(i,`${y.name} ${y.path} ${y.type}`));return n?Se({workspace:n,itemSearchQuery:l??"",expandedFolders:r,showCompletedTasks:f,onItemSearch:w,onBack:S,onItemClick:F,onSessionClick:g,onPinToggle:x,onPinSessionToggle:L,onToggleFolder:R,onToggleTaskComplete:_,onCreateTask:N,onToggleCompletedTasks:o,onStartTask:C,editingTaskId:D,onEditTask:G,onUpdateTask:H,browsePath:e.browsePath,browseEntries:e.browseEntries,breadcrumbs:e.breadcrumbs,browseSearchQuery:e.browseSearchQuery,browseSearchResults:e.browseSearchResults,onBrowseFolder:e.onBrowseFolder,onBrowseSearch:e.onBrowseSearch,onBrowseBack:e.onBrowseBack,onCreateFolder:e.onCreateFolder,onBatchPushToDrive:e.onBatchPushToDrive,onPostToFeed:e.onPostToFeed,onLoadMoreFeed:e.onLoadMoreFeed,onTestConnection:e.onTestConnection,onRemoveConnection:e.onRemoveConnection}):a`
569
+ <div class="workspaces-container" role="region" aria-label="Workspaces">
570
+ <div class="workspaces-toolbar" role="toolbar" aria-label="Workspace controls">
571
+ <form
572
+ class="workspaces-create-form"
573
+ aria-label="Create new workspace"
574
+ @submit=${async y=>{if(y.preventDefault(),$||!O)return;const K=y.currentTarget,q=new FormData(K),X=q.get("name"),J=(typeof X=="string"?X:"").trim();if(!J)return;const Y=q.get("type"),E=(typeof Y=="string"?Y:"project").trim().toLowerCase(),me=E==="team"||E==="personal"?E:"project",Z=q.get("path"),ee=(typeof Z=="string"?Z:"").trim();await O({name:J,type:me,...ee?{path:ee}:{}})!==!1&&K.reset()}}
575
+ >
576
+ <input
577
+ type="text"
578
+ name="name"
579
+ class="workspaces-create-input"
580
+ placeholder="New workspace name (e.g. Acme Corp)"
581
+ aria-label="Workspace name"
582
+ required
583
+ />
584
+ <select name="type" class="workspaces-create-select" aria-label="Workspace type">
585
+ <option value="project">Project</option>
586
+ <option value="team">Team</option>
587
+ <option value="personal">Personal</option>
588
+ </select>
589
+ <input
590
+ type="text"
591
+ name="path"
592
+ class="workspaces-create-input workspaces-create-input--path"
593
+ placeholder="Optional path (auto-created if blank)"
594
+ aria-label="Workspace path (optional)"
595
+ />
596
+ <button
597
+ type="submit"
598
+ class="workspaces-add-btn"
599
+ aria-label="Create workspace"
600
+ ?disabled=${!!$}
601
+ >
602
+ ${$?"Adding...":"Add Workspace"}
603
+ </button>
604
+ </form>
605
+ <input
606
+ type="text"
607
+ class="workspaces-search-input"
608
+ placeholder="Search workspaces..."
609
+ aria-label="Search workspaces"
610
+ .value=${i}
611
+ @input=${y=>T?.(y.target.value)}
612
+ />
613
+ <span class="workspaces-count" aria-live="polite">${U.length} workspaces</span>
614
+ <span class="workspaces-status ${t?"online":"offline"}" role="status">
615
+ ${t?"Online":"Offline"}
616
+ </span>
617
+ ${A?a`<button class="ws-team-setup-btn" aria-label="Start team workspace setup" @click=${()=>A()}>Team Setup</button>`:c}
618
+ </div>
619
+
620
+ ${d?a`<div class="callout danger" role="alert" style="margin: 16px;">${d}</div>`:c}
621
+
622
+ ${p?a`
623
+ <div class="workspaces-loading" role="status" aria-label="Loading workspaces">
624
+ <div class="spinner" aria-hidden="true"></div>
625
+ <span>Loading workspaces...</span>
626
+ </div>
627
+ `:a`
628
+ <div class="workspaces-body">
629
+ <div class="workspace-grid" role="list" aria-label="Workspace list">
630
+ ${U.length===0?a`
631
+ <div class="workspaces-empty">
632
+ <span class="workspaces-empty-icon" aria-hidden="true">${t?"📭":"🔌"}</span>
633
+ <span>${t?"No workspaces yet":"Connect to gateway to see workspaces"}</span>
634
+ ${t?a`<span class="workspaces-empty-hint">Workspaces organize your projects. Ask your ally to create one, or start a focused session in chat.</span>`:c}
635
+ </div>
636
+ `:U.map(y=>ve(y,v,B))}
637
+ </div>
638
+
639
+ ${xe({tasks:m,taskFilter:u,taskSort:k,taskSearch:b,onToggleTaskComplete:_,onSetTaskFilter:I,onSetTaskSort:W,onSetTaskSearch:M,onCreateTask:N,workspaceNames:h,onStartTask:C,editingTaskId:D,onEditTask:G,onUpdateTask:H,onViewTaskOutput:we})}
640
+ </div>
641
+ `}
642
+ </div>
643
+ `}function xe(e){const{tasks:t,taskFilter:s,taskSort:n="due",taskSearch:i="",onToggleTaskComplete:l,onSetTaskFilter:r,onSetTaskSort:p,onSetTaskSearch:$,onCreateTask:d,workspaceNames:m=[],onStartTask:u,editingTaskId:k,onEditTask:b,onUpdateTask:f,onViewTaskOutput:D}=e;if(t.length===0&&!d)return a``;let h;if(s==="outstanding")h=t.filter(w=>w.status==="pending");else if(s==="today"){const w=Q();h=t.filter(v=>v.status==="pending"&&v.dueDate!=null&&v.dueDate<=w)}else s==="complete"?h=t.filter(w=>w.status==="complete"):h=t;if(i){const w=i.toLowerCase();h=h.filter(v=>v.title.toLowerCase().includes(w)||v.project?.toLowerCase().includes(w))}const T=V(h,n);return a`
644
+ <div class="ws-all-tasks-section">
645
+ <section class="ws-section" aria-label="All tasks">
646
+ <div class="ws-section__header">
647
+ <div class="ws-section__header-left">
648
+ <h3>All Tasks</h3>
649
+ ${$?a`<input
650
+ type="text"
651
+ class="ws-task-search"
652
+ placeholder="Search tasks..."
653
+ aria-label="Search tasks"
654
+ .value=${i}
655
+ @input=${w=>$(w.target.value)}
656
+ />`:c}
657
+ </div>
658
+ <div class="ws-task-controls">
659
+ <div class="ws-task-filters" role="group" aria-label="Task filters">
660
+ <button
661
+ class="ws-task-filter-btn ${s==="all"?"active":""}"
662
+ @click=${()=>r?.("all")}
663
+ aria-pressed=${s==="all"}
664
+ >All</button>
665
+ <button
666
+ class="ws-task-filter-btn ${s==="outstanding"?"active":""}"
667
+ @click=${()=>r?.("outstanding")}
668
+ aria-pressed=${s==="outstanding"}
669
+ >To Do</button>
670
+ <button
671
+ class="ws-task-filter-btn ${s==="today"?"active":""}"
672
+ @click=${()=>r?.("today")}
673
+ aria-pressed=${s==="today"}
674
+ >Today</button>
675
+ <button
676
+ class="ws-task-filter-btn ${s==="complete"?"active":""}"
677
+ @click=${()=>r?.("complete")}
678
+ aria-pressed=${s==="complete"}
679
+ >Done</button>
680
+ </div>
681
+ <select
682
+ class="ws-task-sort"
683
+ aria-label="Sort tasks by"
684
+ .value=${n}
685
+ @change=${w=>p?.(w.target.value)}
686
+ >
687
+ <option value="due">Due Date</option>
688
+ <option value="priority">Priority</option>
689
+ <option value="newest">Newest</option>
690
+ </select>
691
+ </div>
692
+ </div>
693
+ ${d?a`
694
+ <form
695
+ class="ws-task-create-form"
696
+ aria-label="Create new task"
697
+ @submit=${w=>{w.preventDefault();const v=w.currentTarget,S=v.querySelector(".ws-task-create-input"),F=v.querySelector(".ws-task-create-project"),g=S.value.trim();if(!g)return;const x=F?.value||m[0]||"";d(g,x),S.value=""}}
698
+ >
699
+ <input
700
+ type="text"
701
+ class="ws-task-create-input"
702
+ placeholder="Add a task..."
703
+ aria-label="New task title"
704
+ />
705
+ ${m.length>0?a`
706
+ <select class="ws-task-create-project" aria-label="Task workspace">
707
+ ${m.map(w=>a`<option value=${w}>${w}</option>`)}
708
+ </select>
709
+ `:c}
710
+ <button type="submit" class="ws-task-create-btn" aria-label="Add task">Add</button>
711
+ </form>
712
+ `:c}
713
+ <div class="ws-list ws-list--scroll" role="list" aria-live="polite" aria-label="Task list">
714
+ ${T.length===0?a`<div class="ws-empty">No tasks</div>`:T.map(w=>$e(w,l,u,k,b,f,D))}
715
+ </div>
716
+ </section>
717
+ </div>
718
+ `}export{$e as a,Re as r,V as s};