@worca/app 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (114) hide show
  1. package/README.md +403 -0
  2. package/agents/clarify.meta.json +19 -0
  3. package/agents/decomposer.meta.json +21 -0
  4. package/agents/implementer.meta.json +20 -0
  5. package/agents/manualTestsChecklist.meta.json +18 -0
  6. package/agents/manualWebUiTesting.meta.json +18 -0
  7. package/agents/planReviewer.meta.json +19 -0
  8. package/agents/planner.meta.json +20 -0
  9. package/agents/refiner.meta.json +19 -0
  10. package/agents/reviewer.meta.json +19 -0
  11. package/agents/worca-cc-clarify.md +67 -0
  12. package/agents/worca-cc-code-reviewer.md +66 -0
  13. package/agents/worca-cc-decomposer.md +84 -0
  14. package/agents/worca-cc-implementer.md +69 -0
  15. package/agents/worca-cc-manual-tests-checklist.md +63 -0
  16. package/agents/worca-cc-manual-web-ui-testing.md +64 -0
  17. package/agents/worca-cc-plan-refiner.md +69 -0
  18. package/agents/worca-cc-plan-reviewer.md +70 -0
  19. package/agents/worca-cc-planner.md +70 -0
  20. package/agents/worca-cc-workspace-reviewer.md +56 -0
  21. package/agents/worca-cc-workspace-scanner.md +55 -0
  22. package/agents/workspaceReviewer.meta.json +20 -0
  23. package/agents/workspaceScanner.meta.json +18 -0
  24. package/package.json +61 -0
  25. package/scripts/install.mjs +209 -0
  26. package/skills/worca/SKILL.md +66 -0
  27. package/src/cli/worca-cc.mjs +1520 -0
  28. package/src/core/agent-gen.mjs +206 -0
  29. package/src/core/agent-registry.mjs +417 -0
  30. package/src/core/agent-store.mjs +143 -0
  31. package/src/core/artifacts.mjs +2019 -0
  32. package/src/core/channels.mjs +302 -0
  33. package/src/core/chat/allowlist.mjs +27 -0
  34. package/src/core/chat/channel-host.mjs +562 -0
  35. package/src/core/chat/channel-protocol.mjs +117 -0
  36. package/src/core/chat/channel-worker-child.mjs +211 -0
  37. package/src/core/chat/chat-context.mjs +66 -0
  38. package/src/core/chat/command-router.mjs +343 -0
  39. package/src/core/chat/notifier.mjs +120 -0
  40. package/src/core/chat/parser.mjs +30 -0
  41. package/src/core/chat/rate-limiter.mjs +133 -0
  42. package/src/core/chat/redact.mjs +27 -0
  43. package/src/core/chat/renderers.mjs +136 -0
  44. package/src/core/claude-runner.mjs +1356 -0
  45. package/src/core/config.mjs +882 -0
  46. package/src/core/cost-budget.mjs +103 -0
  47. package/src/core/db.mjs +864 -0
  48. package/src/core/fanout.mjs +48 -0
  49. package/src/core/folder-dialog.mjs +138 -0
  50. package/src/core/fs-browse.mjs +49 -0
  51. package/src/core/git-info.mjs +200 -0
  52. package/src/core/guardrail-store.mjs +204 -0
  53. package/src/core/guardrails.mjs +302 -0
  54. package/src/core/marketplaces.mjs +267 -0
  55. package/src/core/migrate-fs-to-db.mjs +612 -0
  56. package/src/core/model-env.mjs +74 -0
  57. package/src/core/orchestrator.mjs +4279 -0
  58. package/src/core/overview-agent.mjs +124 -0
  59. package/src/core/phases.mjs +1279 -0
  60. package/src/core/pipeline-delete.mjs +428 -0
  61. package/src/core/plugin-api.mjs +13 -0
  62. package/src/core/plugin-config.mjs +100 -0
  63. package/src/core/plugin-inventory.mjs +50 -0
  64. package/src/core/plugin-manifest.mjs +447 -0
  65. package/src/core/plugin-models.mjs +130 -0
  66. package/src/core/plugin-repo.mjs +303 -0
  67. package/src/core/plugin-shim-child.mjs +76 -0
  68. package/src/core/plugin-shim.mjs +197 -0
  69. package/src/core/plugin-store.mjs +485 -0
  70. package/src/core/plugin-workflows.mjs +179 -0
  71. package/src/core/plugins-lock.mjs +49 -0
  72. package/src/core/preflight-node.mjs +122 -0
  73. package/src/core/preflight.mjs +341 -0
  74. package/src/core/projects.mjs +157 -0
  75. package/src/core/protocol.mjs +257 -0
  76. package/src/core/recoverable-error.mjs +51 -0
  77. package/src/core/results.mjs +188 -0
  78. package/src/core/run-context.mjs +1375 -0
  79. package/src/core/run-log.mjs +64 -0
  80. package/src/core/run-manifest.mjs +317 -0
  81. package/src/core/runners.mjs +167 -0
  82. package/src/core/settings.mjs +682 -0
  83. package/src/core/skills.mjs +210 -0
  84. package/src/core/sources.mjs +232 -0
  85. package/src/core/stats.mjs +182 -0
  86. package/src/core/store.mjs +67 -0
  87. package/src/core/title.mjs +64 -0
  88. package/src/core/workflow-validator.mjs +185 -0
  89. package/src/core/workflows.mjs +568 -0
  90. package/src/core/workspace-scan.mjs +420 -0
  91. package/src/core/workspaces.mjs +353 -0
  92. package/src/core/worktree.mjs +708 -0
  93. package/src/feature.mjs +9 -0
  94. package/ui/public/app.js +10647 -0
  95. package/ui/public/assets/worca-favicon.png +0 -0
  96. package/ui/public/assets/worca-logo.png +0 -0
  97. package/ui/public/chat-settings-view.mjs +89 -0
  98. package/ui/public/composer-core.mjs +211 -0
  99. package/ui/public/fonts/jetbrains-mono-latin-400-normal.woff2 +0 -0
  100. package/ui/public/fonts/poppins-latin-400-normal.woff2 +0 -0
  101. package/ui/public/fonts/poppins-latin-500-normal.woff2 +0 -0
  102. package/ui/public/fonts/poppins-latin-600-normal.woff2 +0 -0
  103. package/ui/public/fonts/poppins-latin-700-normal.woff2 +0 -0
  104. package/ui/public/guardrails-view.mjs +244 -0
  105. package/ui/public/index.html +1145 -0
  106. package/ui/public/log-filter.mjs +81 -0
  107. package/ui/public/log-line.mjs +86 -0
  108. package/ui/public/models-view.mjs +433 -0
  109. package/ui/public/plugins-view.mjs +430 -0
  110. package/ui/public/results-view.mjs +121 -0
  111. package/ui/public/source-pane.mjs +156 -0
  112. package/ui/public/stats-view.mjs +523 -0
  113. package/ui/public/style.css +1557 -0
  114. package/ui/server.mjs +3573 -0
@@ -0,0 +1,1145 @@
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.0" />
6
+ <title>Worca CC</title>
7
+ <link rel="stylesheet" href="/style.css" />
8
+ <meta name="theme-color" content="#ffffff" />
9
+ <link rel="icon" type="image/png" href="/assets/worca-favicon.png" />
10
+ </head>
11
+ <body>
12
+ <div class="app">
13
+ <!-- ===================== Sidebar ===================== -->
14
+ <aside class="sidebar">
15
+ <div class="brand">
16
+ <img class="logo" src="/assets/worca-logo.png" alt="Worca" />
17
+ </div>
18
+
19
+ <nav class="nav" aria-label="Primary">
20
+ <button type="button" class="active nav-cta" data-nav="new">
21
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round"><path d="M12 5v14M5 12h14"></path></svg>
22
+ <span>New pipeline</span>
23
+ </button>
24
+
25
+ <div class="nav-sect">Activity</div>
26
+ <button type="button" data-nav="running">
27
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round"><circle cx="12" cy="12" r="8"></circle><path d="M12 8v4l3 2"></path></svg>
28
+ <span>Running</span>
29
+ <span class="nav-rollup" id="nav-running-rollup" hidden title="A pipeline needs your input"></span>
30
+ <!-- Starts grey: zero running IS the resting state, and app.js
31
+ (updateNavCounts) swaps in n-run as soon as anything is live. -->
32
+ <span class="nav-count n-grey" id="nav-running-count">0</span>
33
+ <span class="nav-count n-paused" id="nav-paused-badge" hidden title="Paused pipelines"><span id="nav-paused-count">0</span><svg class="pause-flag" viewBox="0 0 10 10" aria-hidden="true"><rect x="2.2" y="2" width="2" height="6" rx="1"></rect><rect x="5.8" y="2" width="2" height="6" rx="1"></rect></svg></span>
34
+ </button>
35
+ <div class="nav-children" id="nav-running-children"></div>
36
+ <button type="button" data-nav="history">
37
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round"><path d="M3 12a9 9 0 1 0 3-6.7"></path><path d="M3 4v4h4"></path></svg>
38
+ <span>History</span>
39
+ <span class="nav-count n-grey" id="nav-history-count">0</span>
40
+ </button>
41
+ <button type="button" data-nav="stats">
42
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round"><path d="M5 20v-7M12 20V4M19 20v-11"></path></svg>
43
+ <span>Statistics</span>
44
+ </button>
45
+
46
+ <div class="nav-sect">Build</div>
47
+ <button type="button" data-nav="composer">
48
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="9" width="6" height="6" rx="1.6"></rect><rect x="15" y="4" width="6" height="5.5" rx="1.6"></rect><rect x="15" y="14.5" width="6" height="5.5" rx="1.6"></rect><path d="M9 12h2.5M11.5 12V6.8H15M11.5 12v5.3H15"></path></svg>
49
+ <span>Pipeline Composer</span>
50
+ </button>
51
+ <button type="button" data-nav="agents">
52
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round"><circle cx="9" cy="8" r="3.2"></circle><path d="M3.5 19c.6-3 2.8-4.6 5.5-4.6S13.9 16 14.5 19"></path><circle cx="17.5" cy="9.5" r="2.4"></circle><path d="M15.5 14.6c2.7 0 4.4 1.4 5 4.4"></path></svg>
53
+ <span>Agents</span>
54
+ </button>
55
+ <button type="button" data-nav="guardrails">
56
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round"><path d="M12 3l7 3v5c0 4.6-3 8.4-7 10-4-1.6-7-5.4-7-10V6z"></path></svg>
57
+ <span>Guardrails</span>
58
+ </button>
59
+ <button type="button" data-nav="models">
60
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round"><rect x="7" y="7" width="10" height="10" rx="2"></rect><path d="M12 2v3M12 19v3M2 12h3M19 12h3M6 2.5v2M18 2.5v2M6 19.5v2M18 19.5v2"></path></svg>
61
+ <span>Models</span>
62
+ </button>
63
+ <button type="button" data-nav="plugins">
64
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round"><path d="M9 3v5M15 3v5M7 8h10v4a5 5 0 0 1-10 0V8Z"></path><path d="M12 17v4"></path></svg>
65
+ <span>Plugins</span>
66
+ </button>
67
+
68
+ <div class="nav-sect">Manage</div>
69
+ <button type="button" data-nav="projects">
70
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round"><path d="M3 7.5A1.5 1.5 0 0 1 4.5 6h4l2 2.2H19.5A1.5 1.5 0 0 1 21 9.7v8.3A1.5 1.5 0 0 1 19.5 19.5h-15A1.5 1.5 0 0 1 3 18z"></path></svg>
71
+ <span>Projects</span>
72
+ <span class="nav-count n-grey" id="nav-projects-count">0</span>
73
+ </button>
74
+ <button type="button" data-nav="workspaces">
75
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="7" height="7" rx="1.6"></rect><rect x="14" y="3" width="7" height="7" rx="1.6"></rect><rect x="3" y="14" width="7" height="7" rx="1.6"></rect><path d="M14 17.5h7M17.5 14v7"></path></svg>
76
+ <span>Workspaces</span>
77
+ <span class="nav-count n-grey" id="nav-workspaces-count">0</span>
78
+ </button>
79
+
80
+ <div class="nav-sep" aria-hidden="true"></div>
81
+ <button type="button" data-nav="settings">
82
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="3"></circle><path d="M12.22 2h-.44a2 2 0 0 0-2 2v.18a2 2 0 0 1-1 1.73l-.43.25a2 2 0 0 1-2 0l-.15-.08a2 2 0 0 0-2.73.73l-.22.38a2 2 0 0 0 .73 2.73l.15.1a2 2 0 0 1 1 1.72v.51a2 2 0 0 1-1 1.74l-.15.09a2 2 0 0 0-.73 2.73l.22.38a2 2 0 0 0 2.73.73l.15-.08a2 2 0 0 1 2 0l.43.25a2 2 0 0 1 1 1.73V20a2 2 0 0 0 2 2h.44a2 2 0 0 0 2-2v-.18a2 2 0 0 1 1-1.73l.43-.25a2 2 0 0 1 2 0l.15.08a2 2 0 0 0 2.73-.73l.22-.39a2 2 0 0 0-.73-2.73l-.15-.08a2 2 0 0 1-1-1.74v-.5a2 2 0 0 1 1-1.74l.15-.09a2 2 0 0 0 .73-2.73l-.22-.38a2 2 0 0 0-2.73-.73l-.15.08a2 2 0 0 1-2 0l-.43-.25a2 2 0 0 1-1-1.73V4a2 2 0 0 0-2-2z"></path></svg>
83
+ <span>Settings</span>
84
+ </button>
85
+ </nav>
86
+
87
+ <div class="side-foot">
88
+ <div id="side-spend"></div>
89
+ </div>
90
+ </aside>
91
+
92
+ <!-- ===================== Main ===================== -->
93
+ <main class="main">
94
+ <!-- compact top-nav (shown <1080px, where the sidebar is hidden) -->
95
+ <nav class="topnav" aria-label="Primary compact">
96
+ <button type="button" class="active" data-nav="new">New</button>
97
+ <span class="topnav-sep" aria-hidden="true"></span>
98
+ <button type="button" data-nav="running">Running<span class="nav-rollup" id="topnav-running-rollup" hidden></span></button>
99
+ <button type="button" data-nav="history">History</button>
100
+ <button type="button" data-nav="stats">Stats<span class="topnav-amt mono" id="topnav-spend" hidden></span></button>
101
+ <span class="topnav-sep" aria-hidden="true"></span>
102
+ <button type="button" data-nav="composer">Composer</button>
103
+ <button type="button" data-nav="agents">Agents</button>
104
+ <button type="button" data-nav="guardrails">Guardrails</button>
105
+ <button type="button" data-nav="models">Models</button>
106
+ <button type="button" data-nav="plugins">Plugins</button>
107
+ <span class="topnav-sep" aria-hidden="true"></span>
108
+ <button type="button" data-nav="projects">Projects</button>
109
+ <button type="button" data-nav="workspaces">Workspaces</button>
110
+ <span class="topnav-sep" aria-hidden="true"></span>
111
+ <button type="button" data-nav="settings">Settings</button>
112
+ </nav>
113
+
114
+ <!-- ===== VIEW: NEW PIPELINE ===== -->
115
+ <section class="view" data-view="new">
116
+ <div class="topbar">
117
+ <div>
118
+ <h1>New pipeline</h1>
119
+ <div class="sub">Pick a project, describe the task, and run &middot; agents come tuned &mdash; open one only to change it</div>
120
+ </div>
121
+ </div>
122
+
123
+ <div class="grid single">
124
+ <section class="card">
125
+ <form id="run-form" autocomplete="off">
126
+ <!-- Target switch and the thing it selects share one row: they are one
127
+ decision, and the switch is only meaningful next to its picker. -->
128
+ <div class="split-row">
129
+ <div class="field field-compact">
130
+ <label>Target</label>
131
+ <div class="seg" id="target-seg">
132
+ <button type="button" data-target="project" class="on" aria-pressed="true">Project</button>
133
+ <button type="button" data-target="workspace" aria-pressed="false">Workspace</button>
134
+ </div>
135
+ <!-- hidden radios kept as the source of truth read at submit -->
136
+ <input type="radio" name="target" value="project" checked hidden />
137
+ <input type="radio" name="target" value="workspace" hidden />
138
+ </div>
139
+
140
+ <!-- One cell, two panes: whichever the switch selects. -->
141
+ <div class="target-panes">
142
+
143
+ <!-- Project (target = project) -->
144
+ <div class="field field-compact target-pane" id="target-project-pane">
145
+ <label for="projectSelect">Project</label>
146
+ <div class="select-wrap">
147
+ <select id="projectSelect" name="projectSelect">
148
+ <option value="" disabled selected>No projects yet</option>
149
+ <option value="__add__">+ Add project&hellip;</option>
150
+ </select>
151
+ </div>
152
+ <!-- Removing a project is a rare, destructive action: it lives in the
153
+ Projects view (with the app's own confirm), exactly as removing a
154
+ workspace lives in the Workspaces view. -->
155
+ <small class="hint" id="projectHint">Runs happen inside this folder. <a href="#projects" data-nav="projects">Manage projects</a></small>
156
+
157
+ <div id="add-project" class="add-project hidden">
158
+ <input id="newProjectName" type="text" placeholder="Project name" spellcheck="false" />
159
+ <div class="path-row">
160
+ <input id="newProjectPath" type="text" placeholder="/absolute/path/to/project" spellcheck="false" />
161
+ <button type="button" id="newProjectBrowse" class="btn btn-ghost btn-mini" title="Pick the project folder">Browse&hellip;</button>
162
+ </div>
163
+ <div class="add-project-actions">
164
+ <button type="button" id="addProjectCancel" class="btn btn-ghost btn-mini">Cancel</button>
165
+ <button type="button" id="addProjectSave" class="btn btn-primary btn-mini">Save</button>
166
+ </div>
167
+ <small class="hint" id="addProjectMsg"></small>
168
+ </div>
169
+ </div>
170
+
171
+ <!-- Workspace (target = workspace) -->
172
+ <div class="field field-compact target-pane hidden" id="target-workspace-pane">
173
+ <label for="workspaceSelect">Workspace</label>
174
+ <div class="select-wrap">
175
+ <select id="workspaceSelect" name="workspaceSelect">
176
+ <option value="" disabled selected>No workspaces yet</option>
177
+ </select>
178
+ </div>
179
+ <div class="ws-members" id="ws-members"></div>
180
+ <!-- ONE hint line, matching the project pane: a second line made
181
+ the row taller than its project counterpart, so flipping the
182
+ target relaid out everything below it. -->
183
+ <small class="hint">A run fans out across the member projects. <a href="#workspaces" data-nav="workspaces">Manage workspaces</a></small>
184
+ </div>
185
+
186
+ </div><!-- /.target-panes -->
187
+ </div><!-- /.split-row -->
188
+
189
+ <!-- Title: names the run, so it sits with the task, not behind Advanced. -->
190
+ <div class="field field-compact">
191
+ <label for="title">Title <span class="opt">(optional)</span></label>
192
+ <input id="title" name="title" class="input" type="text" placeholder="Short name for this run" spellcheck="false" />
193
+ <small class="hint">Leave empty and Worca will propose one.</small>
194
+ </div>
195
+
196
+ <!-- Task source switch and the workflow that will act on it, on one
197
+ row — same proportion as Target/Project above. The panes below
198
+ span the full width. -->
199
+ <div class="split-row">
200
+ <div class="field field-compact">
201
+ <label>Task source</label>
202
+ <div class="seg" id="source-seg">
203
+ <button type="button" data-src="prompt" class="on" aria-pressed="true">Prompt</button>
204
+ <button type="button" data-src="markdown" aria-pressed="false">Markdown</button>
205
+ </div>
206
+ <!-- hidden radios kept as the source of truth read at submit -->
207
+ <input type="radio" name="source" value="prompt" checked hidden />
208
+ <input type="radio" name="source" value="markdown" hidden />
209
+ </div>
210
+
211
+ <!-- Workflow picker (Default + saved). app.js populates from GET
212
+ /api/workflows. Choosing a workflow is a run decision, so it
213
+ stays here; tuning its agents is not, and lives in Advanced. -->
214
+ <div class="field field-compact">
215
+ <label for="workflowSelect">Workflow</label>
216
+ <div class="select-wrap">
217
+ <select id="workflowSelect" class="select" aria-label="Workflow">
218
+ <option value="wf_default">Default</option>
219
+ </select>
220
+ </div>
221
+ </div>
222
+ </div>
223
+
224
+ <div class="field">
225
+ <div id="prompt-pane" class="source-pane">
226
+ <textarea id="prompt" name="prompt" class="textarea" rows="6" style="margin-top:11px" placeholder="Describe the software task to build&hellip;"></textarea>
227
+ </div>
228
+
229
+ <div id="markdown-pane" class="source-pane hidden">
230
+ <textarea id="promptMarkdown" name="promptMarkdown" class="textarea" rows="6" style="margin-top:11px" placeholder="Paste a markdown spec, or load a .md file below&hellip;"></textarea>
231
+ <div class="file" style="margin-top:11px">
232
+ <button type="button" class="pick" data-pick="md">Load .md file</button>
233
+ <span id="mdFileName" class="state hint"></span>
234
+ <input id="mdFile" type="file" accept=".md,.markdown,text/markdown,text/plain" hidden />
235
+ </div>
236
+ </div>
237
+ <div id="plugin-source-pane" class="source-pane hidden"></div>
238
+ </div>
239
+
240
+ <!-- Config-load failure hint; app.js#setConfigError paints/clears it.
241
+ Lives in the main column: it reports that the model catalog and
242
+ saved agent config could not be read, and Advanced never opens
243
+ itself, so inside it the message would go unseen. -->
244
+ <div id="config-error" class="hint" style="margin:-6px 0 14px;color:var(--red-ink)" hidden></div>
245
+
246
+ <!-- Extra files belong WITH the task: they are more of the same
247
+ input, just as files. -->
248
+ <div class="field field-compact">
249
+ <label>Extra files <span class="opt">(optional)</span></label>
250
+ <div class="file">
251
+ <button type="button" class="pick" data-pick="extras">Choose files</button>
252
+ <span class="state" id="extrasNote">Leave empty and the run gets no extra files.</span>
253
+ <input id="extras" type="file" multiple hidden />
254
+ </div>
255
+ </div>
256
+
257
+ <!-- Branch pair: one decision (from → into), so one compact row. -->
258
+ <div class="field-grid-2">
259
+ <div class="field field-compact">
260
+ <label for="sourceBranch">Source branch</label>
261
+ <div class="select-wrap" id="sourceBranchWrap">
262
+ <select id="sourceBranch" class="select"></select>
263
+ </div>
264
+ <!-- Workspace mode: one source-branch dropdown per member project. -->
265
+ <div class="ws-source-branches hidden" id="ws-source-branches"></div>
266
+ <small class="hint" id="sourceBranchHint">The worktree branches off this. Defaults to the current branch.</small>
267
+ </div>
268
+
269
+ <div class="field field-compact">
270
+ <label for="featureBranch">Feature branch <span class="opt">(optional)</span></label>
271
+ <input id="featureBranch" class="input" type="text" placeholder="e.g. feat/rate-limiter" spellcheck="false" />
272
+ <small class="hint">Leave empty and Worca will propose one.</small>
273
+ </div>
274
+ </div>
275
+
276
+ <!-- Advanced: how the run is executed, as opposed to what it runs.
277
+ A workflow ships tuned, so its per-agent knobs belong here with
278
+ guardrails and mock mode; the workflow PICKER stays above.
279
+ Collapsed unless something inside is already non-default. -->
280
+ <details class="advanced" id="advanced-config">
281
+ <summary>
282
+ <span class="adv-chev" aria-hidden="true"></span>
283
+ <span>Advanced</span>
284
+ </summary>
285
+ <div class="advanced-body">
286
+
287
+ <div id="pipeline-config">
288
+
289
+ <!-- Agents accordion: one collapsed row per node, showing its
290
+ EFFECTIVE model/effort. app.js#renderAgentRows fills it. The
291
+ header names the workflow these agents come from — the picker
292
+ is no longer beside them. -->
293
+ <div class="agents-cfg" id="agents-config">
294
+ <div class="agents-head">
295
+ <span class="agents-title">Agents</span>
296
+ <span class="agents-wf" id="agentsWorkflow"></span>
297
+ <span class="agents-summary" id="agentsSummary">all defaults</span>
298
+ <span class="agents-actions">
299
+ <button type="button" id="agentsPromote" class="btn-ghost btn-mini" hidden>Save as workflow defaults</button>
300
+ <button type="button" id="agentsReset" class="btn-ghost btn-mini" hidden>Reset</button>
301
+ </span>
302
+ </div>
303
+ <div id="agents-rows"></div>
304
+ <div id="wf-feedback-config" class="agent-row-body-inner" hidden></div>
305
+ </div>
306
+ </div>
307
+
308
+ <!-- Guardrails picker (built-ins + named sets; the selection IS the
309
+ run's policy, applied uniformly to every member). app.js populates
310
+ from GET /api/guardrails. Applies to Project and Workspace targets
311
+ alike. Default Permissive = no restrictions (legacy behavior). -->
312
+ <div class="field">
313
+ <label for="guardrailsSelect">Guardrails</label>
314
+ <div class="select-wrap">
315
+ <select id="guardrailsSelect" class="select" aria-label="Guardrails">
316
+ <option value="permissive">Permissive (default)</option>
317
+ </select>
318
+ </div>
319
+ <small class="hint" id="guardrailsHint">Applies to every agent this run spawns. Permissive = no restrictions (the legacy default).</small>
320
+ </div>
321
+
322
+ <div class="switch-row">
323
+ <div class="switch" id="mock-switch" role="switch" aria-checked="false" tabindex="0"></div>
324
+ <span class="txt">Mock mode — no Claude calls, offline dry run</span>
325
+ </div>
326
+ <input id="mock" type="checkbox" hidden />
327
+ </div>
328
+ </details>
329
+
330
+ <!-- Actions -->
331
+ <div class="hint err" id="newBlockedNote" hidden></div>
332
+ <div class="actions" style="justify-content:flex-end">
333
+ <button type="submit" id="start-btn" class="btn-go">
334
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor"><path d="M6 4l14 8-14 8V4Z"></path></svg>
335
+ Start run
336
+ </button>
337
+ </div>
338
+ <p id="form-msg" class="form-msg" aria-live="polite"></p>
339
+ </form>
340
+ </section>
341
+ </div>
342
+ </section>
343
+ <!-- /view new -->
344
+
345
+ <!-- ===== VIEW: RUNNING ===== -->
346
+ <section class="view hidden" data-view="running">
347
+ <div class="topbar">
348
+ <div>
349
+ <h1>Running</h1>
350
+ <div class="sub" id="running-sub">0 pipelines executing · 0 need your input</div>
351
+ </div>
352
+ <span class="pill-run amber hidden" id="running-status-pill" style="box-shadow:var(--shadow-soft)"><span class="pdot"></span> 0 needs input</span>
353
+ </div>
354
+
355
+ <div class="run-list" id="run-list"></div>
356
+
357
+ <!-- clone target for one run card (Task 3 fills it) -->
358
+ <template id="run-card-tpl">
359
+ <section class="card run-card" data-run-id="">
360
+ <div class="run-top">
361
+ <div><div class="run-title"></div><div class="run-meta"><span class="rm-text"></span><span class="run-time mono"></span><span class="run-cost mono"></span></div></div>
362
+ <span class="pill-run"><span class="pdot"></span><span class="pill-text"></span></span>
363
+ </div>
364
+ <div class="run-flow-wrap"><div class="run-flow"></div></div>
365
+ <div class="run-foot"><span class="chip"></span><button type="button" class="btn-resume sm" title="Resume — restart this paused pipeline where it left off" hidden><svg width="11" height="11" viewBox="0 0 24 24" fill="currentColor"><path d="M7 5l12 7-12 7z"></path></svg> Resume</button><button type="button" class="btn-pause sm" title="Pause — gracefully stop the session so it can be resumed"><svg width="11" height="11" viewBox="0 0 24 24" fill="currentColor"><rect x="6" y="5" width="4" height="14" rx="1.5"></rect><rect x="14" y="5" width="4" height="14" rx="1.5"></rect></svg> Pause</button><button type="button" class="btn-stop sm"><svg width="11" height="11" viewBox="0 0 24 24" fill="currentColor"><rect x="6" y="6" width="12" height="12" rx="2"></rect></svg> Stop</button></div>
366
+ <div class="cost-banner" hidden></div>
367
+ <div class="subs-bar" hidden>
368
+ <button type="button" class="btn-subs" aria-expanded="false">
369
+ <svg class="ico" viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="6" cy="6" r="2.4"/><circle cx="6" cy="18" r="2.4"/><circle cx="18" cy="12" r="2.4"/><path d="M8 6h5a3 3 0 0 1 3 3v0M8 18h5a3 3 0 0 0 3-3v0" stroke-linecap="round"/></svg>
370
+ Agents
371
+ <span class="sb-count grey"></span>
372
+ <svg class="chev" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2"><path d="M6 9l6 6 6-6" stroke-linecap="round" stroke-linejoin="round"/></svg>
373
+ </button>
374
+ <div class="subs-panel" hidden></div>
375
+ </div>
376
+ <div class="run-log">
377
+ <div class="run-log-head"><span class="ll-label">Live log</span><div class="log-filters"><select class="log-f log-f-source" title="Filter by source" aria-label="Filter by source"></select><select class="log-f log-f-level" title="Filter by level" aria-label="Filter by level"></select><select class="log-f log-f-step" title="Filter by step" aria-label="Filter by step"></select><select class="log-f log-f-cycle" title="Filter by cycle" aria-label="Filter by cycle"></select><input type="search" class="log-f log-search" placeholder="search" title="Search the log text" aria-label="Search the log text"><button type="button" class="log-f log-copy" title="Copy the visible log lines" aria-label="Copy the visible log lines">copy</button></div><div class="switch-row"><div class="switch on autoscroll" role="switch" aria-checked="true" tabindex="0"></div><span class="txt">Auto-scroll</span></div></div>
378
+ <div class="log"></div>
379
+ </div>
380
+ <div class="qpanel hidden"></div>
381
+ </section>
382
+ </template>
383
+ </section>
384
+ <!-- /view running -->
385
+
386
+ <!-- ===== VIEW: HISTORY ===== -->
387
+ <section class="view hidden" data-view="history">
388
+ <div class="topbar">
389
+ <div>
390
+ <h1>History</h1>
391
+ <div class="sub">Completed and stopped pipelines</div>
392
+ </div>
393
+ <button type="button" id="refresh-history" class="btn-ghost" style="padding:11px 20px">Refresh</button>
394
+ </div>
395
+
396
+ <!-- Project filter pills: "All Projects" + one per project that has history.
397
+ Built by renderHistoryPills() from the /api/history dataset. -->
398
+ <div class="hist-filter" id="historyFilter" aria-label="Filter history by project"></div>
399
+
400
+ <div class="run-list" id="history"></div>
401
+
402
+ <!-- clone target for one history card (Task 5 fills it) -->
403
+ <template id="hist-card-tpl">
404
+ <section class="card hist-card">
405
+ <div class="hist-head" role="button" tabindex="0" aria-expanded="false">
406
+ <span class="badge"></span>
407
+ <span class="badge hist-retained-badge" hidden>Work retained</span>
408
+ <div class="h-meta">
409
+ <b></b><small></small><span class="hist-time mono"></span><span class="hist-total mono"></span>
410
+ <span class="hist-branch mono"></span>
411
+ <span class="hist-pausenote" hidden></span>
412
+ </div>
413
+ <div class="hist-aside">
414
+ <span class="hist-diff" aria-label="lines changed"></span>
415
+ <span class="hist-merge" hidden></span>
416
+ <button type="button" class="hist-pr btn-ghost" hidden>Create PR</button>
417
+ <button type="button" class="hist-resume btn-ghost" hidden>Resume</button>
418
+ </div>
419
+ <svg class="chev" width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4"><path d="M6 9l6 6 6-6" stroke-linecap="round" stroke-linejoin="round"></path></svg>
420
+ </div>
421
+ <div class="hist-detail" hidden>
422
+ <div class="retained-banner" role="alert" hidden></div>
423
+ <div class="run-flow-wrap"><div class="run-flow"></div></div>
424
+ <!-- Results view (Layer 1 mechanical + Layer 2 overview) -->
425
+ <div class="results-section"></div>
426
+ <!-- Diff dropdown (New/Changed files) — collapsed by default -->
427
+ <div class="diff-bar" hidden>
428
+ <button type="button" class="btn-subs" aria-expanded="false">
429
+ <svg class="ico" viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M6 3h8l4 4v14H6z" stroke-linejoin="round"/><path d="M14 3v4h4" stroke-linejoin="round"/></svg>
430
+ Diff
431
+ <span class="sb-count diff-changed grey"></span>
432
+ <span class="sb-count diff-removed grey"></span>
433
+ <svg class="chev" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2"><path d="M6 9l6 6 6-6" stroke-linecap="round" stroke-linejoin="round"/></svg>
434
+ </button>
435
+ <div class="subs-panel diff-panel" hidden></div>
436
+ </div>
437
+ <!-- Overview dropdown (Layer-2 summary) — collapsed; Generate button built on first expand -->
438
+ <div class="overview-bar" hidden>
439
+ <button type="button" class="btn-subs" aria-expanded="false">
440
+ <svg class="ico" viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="12" cy="12" r="8"/><path d="M12 8h.01M11 12h1v4h1" stroke-linecap="round" stroke-linejoin="round"/></svg>
441
+ Overview
442
+ <svg class="chev" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2"><path d="M6 9l6 6 6-6" stroke-linecap="round" stroke-linejoin="round"/></svg>
443
+ </button>
444
+ <div class="subs-panel overview-panel" hidden></div>
445
+ </div>
446
+ <div class="subs-bar" hidden>
447
+ <button type="button" class="btn-subs" aria-expanded="false">
448
+ <svg class="ico" viewBox="0 0 24 24" fill="none" stroke="currentColor"><circle cx="6" cy="6" r="2.4"/><circle cx="6" cy="18" r="2.4"/><circle cx="18" cy="12" r="2.4"/><path d="M8 6h5a3 3 0 0 1 3 3v0M8 18h5a3 3 0 0 0 3-3v0" stroke-linecap="round"/></svg>
449
+ Agents
450
+ <span class="sb-count grey"></span>
451
+ <svg class="chev" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2"><path d="M6 9l6 6 6-6" stroke-linecap="round" stroke-linejoin="round"/></svg>
452
+ </button>
453
+ <div class="subs-panel" hidden></div>
454
+ </div>
455
+ <!-- Clarify dropdown (Q&A) — under Sub-agents -->
456
+ <div class="clarify-bar" hidden>
457
+ <button type="button" class="btn-subs" aria-expanded="false">
458
+ <svg class="ico" viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M9.5 9a2.5 2.5 0 1 1 3.5 2.3c-.9.4-1.5 1-1.5 2.2M12 17h.01" stroke-linecap="round" stroke-linejoin="round"/></svg>
459
+ Clarify
460
+ <span class="sb-count grey"></span>
461
+ <svg class="chev" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2"><path d="M6 9l6 6 6-6" stroke-linecap="round" stroke-linejoin="round"/></svg>
462
+ </button>
463
+ <div class="subs-panel clarify-panel" hidden></div>
464
+ </div>
465
+ <!-- Live logs dropdown — under Clarify -->
466
+ <div class="logs-bar" hidden>
467
+ <button type="button" class="btn-subs" aria-expanded="false">
468
+ <svg class="ico" viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M4 6h16M4 12h16M4 18h10" stroke-linecap="round"/></svg>
469
+ Live logs
470
+ <svg class="chev" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2"><path d="M6 9l6 6 6-6" stroke-linecap="round" stroke-linejoin="round"/></svg>
471
+ </button>
472
+ <div class="subs-panel logs-panel" hidden></div>
473
+ </div>
474
+ <div class="hist-actions">
475
+ <button type="button" class="hist-discard btn-ghost" hidden>Discard worktree</button>
476
+ <button type="button" class="hist-delete btn-danger" hidden>
477
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor"
478
+ stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
479
+ <path d="M3 6h18M8 6V4a1 1 0 0 1 1-1h6a1 1 0 0 1 1 1v2m2 0v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6"></path>
480
+ <line x1="10" y1="11" x2="10" y2="17"></line><line x1="14" y1="11" x2="14" y2="17"></line>
481
+ </svg>
482
+ Archive
483
+ </button>
484
+ </div>
485
+ </div>
486
+ </section>
487
+ </template>
488
+ </section>
489
+ <!-- /view history -->
490
+
491
+ <!-- ===== VIEW: STATISTICS ===== -->
492
+ <section class="view hidden" data-view="stats">
493
+ <div class="topbar">
494
+ <div>
495
+ <h1>Statistics</h1>
496
+ <div class="sub">Spend, time worked, and outcomes across all pipelines · costs are Claude Code estimates, not billing</div>
497
+ </div>
498
+ </div>
499
+ <div class="stats-filter">
500
+ <div class="seg" id="stats-range" role="group" aria-label="Time range">
501
+ <button type="button" data-range="today">Today</button>
502
+ <button type="button" data-range="week">This week</button>
503
+ <button type="button" data-range="month">This month</button>
504
+ <button type="button" data-range="all">All time</button>
505
+ </div>
506
+ </div>
507
+ <div id="stats-body"><small class="hint">Loading…</small></div>
508
+ <div id="stats-tip" class="chart-tip" hidden></div>
509
+ </section>
510
+ <!-- /view stats -->
511
+
512
+ <!-- ===== VIEW: WORKSPACES ===== -->
513
+ <section class="view hidden" data-view="workspaces">
514
+ <div class="topbar">
515
+ <div>
516
+ <h1>Workspaces</h1>
517
+ <div class="sub">Named sets of 2+ projects with an AI-generated interconnection description</div>
518
+ </div>
519
+ <button type="button" id="ws-create-btn" class="btn-go" style="padding:11px 20px">
520
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round"><path d="M12 5v14M5 12h14"></path></svg>
521
+ Create workspace
522
+ </button>
523
+ </div>
524
+
525
+ <p id="ws-msg" class="form-msg" aria-live="polite"></p>
526
+
527
+ <div class="run-list" id="ws-list"></div>
528
+
529
+ <!-- clone target for one workspace card -->
530
+ <template id="ws-card-tpl">
531
+ <section class="card ws-card">
532
+ <div class="ws-head" role="button" tabindex="0" aria-expanded="false">
533
+ <div class="ws-h-meta">
534
+ <b class="ws-name"></b>
535
+ <span class="ws-stale badge red" hidden>missing projects</span>
536
+ <small class="ws-projects"></small>
537
+ </div>
538
+ <div class="ws-actions">
539
+ <button type="button" class="ws-edit btn-ghost" title="Edit description">Edit description</button>
540
+ <button type="button" class="ws-rescan btn-ghost" title="Re-scan the project set">Re-scan</button>
541
+ <button type="button" class="ws-delete btn-danger" title="Delete workspace">Delete</button>
542
+ </div>
543
+ <svg class="chev" width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4"><path d="M6 9l6 6 6-6" stroke-linecap="round" stroke-linejoin="round"></path></svg>
544
+ </div>
545
+ <div class="ws-detail" hidden>
546
+ <pre class="ws-desc-view viewer"></pre>
547
+ <div class="ws-desc-edit" hidden>
548
+ <textarea class="ws-desc-input textarea" rows="10" spellcheck="false"></textarea>
549
+ <div class="actions" style="justify-content:flex-end;margin-top:10px">
550
+ <button type="button" class="ws-desc-cancel btn btn-ghost btn-mini">Cancel</button>
551
+ <button type="button" class="ws-desc-save btn btn-primary btn-mini">Save</button>
552
+ </div>
553
+ </div>
554
+ </div>
555
+ </section>
556
+ </template>
557
+ </section>
558
+ <!-- /view workspaces -->
559
+
560
+ <!-- ===== VIEW: WORKSPACE CREATE (wizard) ===== -->
561
+ <section class="view hidden" data-view="workspace-create">
562
+ <div class="topbar">
563
+ <div>
564
+ <h1 id="wiz-title">Create workspace</h1>
565
+ <div class="sub">Pick 2+ projects, scan their interconnections, then save</div>
566
+ </div>
567
+ <button type="button" id="wiz-close" class="btn-ghost" style="padding:11px 20px">Cancel</button>
568
+ </div>
569
+
570
+ <section class="card" style="max-width:820px">
571
+ <!-- Step 1: name + project multi-select -->
572
+ <div class="wiz-step" id="wiz-step-1">
573
+ <div class="field">
574
+ <label for="wiz-name">Workspace name</label>
575
+ <input id="wiz-name" class="input" type="text" placeholder="e.g. IoT SP Platform" spellcheck="false" />
576
+ </div>
577
+ <div class="field">
578
+ <label>Projects <span class="opt">(select 2 or more)</span></label>
579
+ <div class="wiz-proj-list" id="wiz-projects"></div>
580
+ <small class="hint" id="wiz-step1-hint">Onboard at least two projects to create a workspace.</small>
581
+ </div>
582
+ <div class="actions" style="justify-content:flex-end">
583
+ <button type="button" id="wiz-start-scan" class="btn-go" disabled>
584
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round"><path d="M5 12h14M13 6l6 6-6 6"></path></svg>
585
+ Scan interconnections
586
+ </button>
587
+ </div>
588
+ </div>
589
+
590
+ <!-- Step 2: live scan loader -->
591
+ <div class="wiz-step hidden" id="wiz-step-2">
592
+ <div class="ws-loader" role="status" aria-live="polite">
593
+ <div class="spinner" aria-hidden="true"></div>
594
+ <div class="status-label" id="wiz-status">Starting scan&hellip;</div>
595
+ <div class="status-sub" id="wiz-progress"></div>
596
+ </div>
597
+ <div class="wiz-phase-track" id="wiz-phases">
598
+ <span data-phase="graph">Graph</span>
599
+ <span data-phase="investigate">Investigate</span>
600
+ <span data-phase="synthesize">Synthesize</span>
601
+ </div>
602
+ <div class="actions" style="justify-content:flex-end">
603
+ <button type="button" id="wiz-abort" class="btn btn-ghost btn-mini">Abort scan</button>
604
+ </div>
605
+ </div>
606
+
607
+ <!-- Step 3: editable description -->
608
+ <div class="wiz-step hidden" id="wiz-step-3">
609
+ <div class="field">
610
+ <label for="wiz-desc">Interconnection description <span class="opt">(editable)</span></label>
611
+ <textarea id="wiz-desc" class="textarea" rows="16" spellcheck="false" placeholder="# Workspace: ..."></textarea>
612
+ <small class="hint" id="wiz-graphify-note"></small>
613
+ </div>
614
+ <p id="wiz-msg" class="form-msg" aria-live="polite"></p>
615
+ <div class="actions" style="justify-content:space-between">
616
+ <button type="button" id="wiz-rescan" class="btn btn-ghost btn-mini">Re-scan</button>
617
+ <button type="button" id="wiz-save" class="btn-go">
618
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4"><path d="M5 13l4 4L19 7" stroke-linecap="round" stroke-linejoin="round"></path></svg>
619
+ Save workspace
620
+ </button>
621
+ </div>
622
+ </div>
623
+ </section>
624
+ </section>
625
+ <!-- /view workspace-create -->
626
+
627
+ <!-- ===== VIEW: AGENTS ===== -->
628
+ <section class="view hidden" data-view="agents">
629
+ <div class="topbar">
630
+ <div>
631
+ <h1>Agents</h1>
632
+ <div class="sub">Built-in and custom agents — what each consumes and produces drives the Composer</div>
633
+ </div>
634
+ <button type="button" id="agent-create-btn" class="btn-go" style="padding:11px 20px">
635
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round"><path d="M12 5v14M5 12h14"></path></svg>
636
+ Create agent
637
+ </button>
638
+ </div>
639
+ <p id="agents-msg" class="form-msg" aria-live="polite"></p>
640
+ <div class="run-list" id="agents-list"></div>
641
+
642
+ <template id="agent-card-tpl">
643
+ <section class="card agent-card">
644
+ <div class="agent-head" role="button" tabindex="0" aria-expanded="false">
645
+ <div class="agent-h-meta">
646
+ <b class="agent-name"></b>
647
+ <span class="agent-origin badge"></span>
648
+ <small class="agent-sub"></small>
649
+ <div class="agent-io">
650
+ <div class="agent-io-row agent-io-in">
651
+ <span class="agent-io-label">Input</span>
652
+ <div class="agent-chips agent-chips-in"></div>
653
+ </div>
654
+ <div class="agent-io-row agent-io-out">
655
+ <span class="agent-io-label">Output</span>
656
+ <div class="agent-chips agent-chips-out"></div>
657
+ </div>
658
+ </div>
659
+ </div>
660
+ <div class="agent-actions">
661
+ <button type="button" class="agent-edit btn-ghost" title="Edit this agent">Edit</button>
662
+ <button type="button" class="agent-duplicate btn-ghost" title="Duplicate as a user agent">Duplicate</button>
663
+ <button type="button" class="agent-delete btn-danger" title="Delete this agent">Delete</button>
664
+ </div>
665
+ <svg class="chev" width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4"><path d="M6 9l6 6 6-6" stroke-linecap="round" stroke-linejoin="round"></path></svg>
666
+ </div>
667
+ <div class="agent-detail" hidden>
668
+ <pre class="agent-md-view viewer"></pre>
669
+ <div class="agent-edit-pane" hidden>
670
+ <div class="field"><label>Display name</label><input class="agent-f-name input" type="text" spellcheck="false" /></div>
671
+ <div class="field"><label>Description</label><input class="agent-f-desc input" type="text" spellcheck="false" /></div>
672
+ <div class="row-2">
673
+ <div class="field"><label>Color</label>
674
+ <div class="select-wrap"><select class="agent-f-color select">
675
+ <option>green</option><option>peach</option><option>red</option>
676
+ <option>blue</option><option>violet</option><option>amber</option>
677
+ </select></div>
678
+ </div>
679
+ <div class="field"><label>Runner type</label>
680
+ <div class="select-wrap"><select class="agent-f-runner select">
681
+ <option>producer</option><option>verifier</option>
682
+ </select></div>
683
+ </div>
684
+ </div>
685
+ <div class="field"><label>Consumes</label><div class="agent-f-consumes chip-select"></div></div>
686
+ <div class="field"><label>Optional consumes</label><div class="agent-f-optional chip-select"></div></div>
687
+ <div class="field"><label>Produces</label><div class="agent-f-produces chip-select"></div></div>
688
+ <div class="field"><label>Connects to</label>
689
+ <label class="fanout-toggle"><input type="checkbox" class="agent-f-connect-any" /><span>any agent (*)</span></label>
690
+ <div class="agent-f-connects chip-select"></div>
691
+ </div>
692
+ <div class="row-2">
693
+ <div class="field"><label>Order</label><input class="agent-f-order input" type="number" step="0.1" /></div>
694
+ <div class="field"><label>Flags</label>
695
+ <label class="fanout-toggle"><input type="checkbox" class="agent-f-fanout" /><span>Fan-out</span></label>
696
+ <label class="fanout-toggle"><input type="checkbox" class="agent-f-loopsource" /><span>Loop source</span></label>
697
+ <label class="fanout-toggle"><input type="checkbox" class="agent-f-questions" /><span>Asks questions</span></label>
698
+ <label class="fanout-toggle"><input type="checkbox" class="agent-f-questions-locked" /><span>Questions locked</span></label>
699
+ <label class="fanout-toggle"><input type="checkbox" class="agent-f-questions-default" /><span>Questions on by default</span></label>
700
+ </div>
701
+ </div>
702
+ <div class="field"><label>System prompt (markdown)</label>
703
+ <textarea class="agent-f-md textarea" rows="16" spellcheck="false"></textarea>
704
+ </div>
705
+ <p class="agent-edit-msg form-msg" aria-live="polite"></p>
706
+ <div class="actions" style="justify-content:flex-end">
707
+ <button type="button" class="agent-edit-cancel btn btn-ghost btn-mini">Cancel</button>
708
+ <button type="button" class="agent-edit-save btn btn-primary btn-mini">Save</button>
709
+ </div>
710
+ </div>
711
+ </div>
712
+ </section>
713
+ </template>
714
+ </section>
715
+ <!-- /view agents -->
716
+
717
+ <!-- ===== VIEW: PLUGINS ===== -->
718
+ <section class="view hidden" data-view="plugins">
719
+ <div class="topbar">
720
+ <div>
721
+ <h1>Plugins</h1>
722
+ <div class="sub">Task sources, agents, skills and workflow packs from your plugin marketplaces</div>
723
+ </div>
724
+ <button type="button" id="plugin-add-btn" class="btn-go" style="padding:11px 20px">
725
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round"><path d="M12 5v14M5 12h14"></path></svg>
726
+ Add marketplace
727
+ </button>
728
+ </div>
729
+ <p id="plugins-msg" class="form-msg" aria-live="polite"></p>
730
+ <div class="card hidden" id="marketplace-add-row" style="padding:16px 20px;margin-bottom:14px">
731
+ <div class="path-row">
732
+ <input id="marketplace-url" class="input" type="text" placeholder="https://github.com/owner/repo · owner/repo · /abs/path/to/repo" spellcheck="false" />
733
+ <button type="button" id="marketplace-add" class="btn btn-primary btn-mini">Add</button>
734
+ </div>
735
+ </div>
736
+ <h3 class="pl-sec-title">Installed</h3>
737
+ <div class="run-list" id="plugins-list"></div>
738
+ <h3 class="pl-sec-title">Available</h3>
739
+ <div class="run-list" id="plugins-available"></div>
740
+ <h3 class="pl-sec-title">Marketplaces</h3>
741
+ <div class="run-list" id="marketplaces-list"></div>
742
+ </section>
743
+ <!-- /view plugins -->
744
+
745
+ <!-- ===== VIEW: GUARDRAILS ===== -->
746
+ <section class="view hidden" data-view="guardrails">
747
+ <div class="topbar">
748
+ <div>
749
+ <h1>Guardrails</h1>
750
+ <div class="sub">Named guardrail policies — built-ins plus your own sets, selected per pipeline run</div>
751
+ </div>
752
+ <button type="button" id="guardrail-create-btn" class="btn-go" style="padding:11px 20px">
753
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round"><path d="M12 5v14M5 12h14"></path></svg>
754
+ Create guardrails
755
+ </button>
756
+ </div>
757
+ <p id="guardrails-msg" class="form-msg" aria-live="polite"></p>
758
+ <div class="run-list" id="guardrails-list"></div>
759
+ </section>
760
+ <!-- /view guardrails -->
761
+
762
+ <!-- ===== VIEW: MODELS ===== -->
763
+ <section class="view hidden" data-view="models">
764
+ <div class="topbar">
765
+ <div>
766
+ <h1>Models</h1>
767
+ <div class="sub">Global model catalog — available in every project; entries can override built-ins and carry per-model routing env</div>
768
+ </div>
769
+ <div style="display:flex;gap:8px">
770
+ <button type="button" id="model-share-btn" class="btn-ghost" style="padding:11px 20px">Share as plugin…</button>
771
+ <button type="button" id="model-create-btn" class="btn-go" style="padding:11px 20px">
772
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round"><path d="M12 5v14M5 12h14"></path></svg>
773
+ Add model
774
+ </button>
775
+ </div>
776
+ </div>
777
+ <p id="models-msg" class="form-msg" aria-live="polite"></p>
778
+ <div class="run-list" id="models-list"></div>
779
+ </section>
780
+ <!-- /view models -->
781
+
782
+ <!-- ===== VIEW: PROJECTS ===== -->
783
+ <section class="view hidden" data-view="projects">
784
+ <div class="topbar">
785
+ <div>
786
+ <h1>Projects</h1>
787
+ <div class="sub">Registered projects. Add a folder or remove one from the list — files on disk and run history are never touched.</div>
788
+ </div>
789
+ <button type="button" id="project-add-btn" class="btn btn-primary btn-mini">
790
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round"><path d="M12 5v14M5 12h14"></path></svg>
791
+ Add project
792
+ </button>
793
+ </div>
794
+ <p id="projects-msg" class="form-msg" aria-live="polite"></p>
795
+ <div class="run-list" id="projects-list"></div>
796
+ </section>
797
+ <!-- /view projects -->
798
+
799
+ <!-- ===== VIEW: AGENT CREATE (wizard) ===== -->
800
+ <section class="view hidden" data-view="agent-create">
801
+ <div class="topbar">
802
+ <div>
803
+ <h1>Create agent</h1>
804
+ <div class="sub">Describe the agent, let the builder draft it, then review and save</div>
805
+ </div>
806
+ <button type="button" id="agw-close" class="btn-ghost" style="padding:11px 20px">Cancel</button>
807
+ </div>
808
+
809
+ <section class="card" style="max-width:820px">
810
+ <!-- Step 1: brief -->
811
+ <div class="wiz-step" id="agw-step-1">
812
+ <div class="field"><label for="agw-name">Agent name</label>
813
+ <input id="agw-name" class="input" type="text" placeholder="e.g. Docs Writer" spellcheck="false" /></div>
814
+ <div class="field"><label for="agw-purpose">Purpose <span class="opt">(one line)</span></label>
815
+ <input id="agw-purpose" class="input" type="text" placeholder="What is this agent for?" spellcheck="false" /></div>
816
+ <div class="field"><label for="agw-details">Detailed description</label>
817
+ <textarea id="agw-details" class="textarea" rows="6" placeholder="Inputs, method, output contract, constraints&hellip;"></textarea></div>
818
+ <div class="row-2">
819
+ <div class="field"><label>Runs after <span class="opt">(predecessors)</span></label>
820
+ <div id="agw-before" class="chip-select"></div></div>
821
+ <div class="field"><label>Runs before <span class="opt">(successors)</span></label>
822
+ <div id="agw-after" class="chip-select"></div></div>
823
+ </div>
824
+ <div class="switch-row" style="margin-top:14px">
825
+ <div class="switch" id="agw-own-md-toggle" role="switch" aria-checked="false" tabindex="0"></div>
826
+ <span class="txt">I'll provide the markdown myself — the builder only infers the metadata</span>
827
+ </div>
828
+ <div id="agw-own-md-pane" class="hidden" style="margin-top:11px">
829
+ <textarea id="agw-own-md" class="textarea" rows="12" spellcheck="false" placeholder="Paste your agent system prompt markdown&hellip;"></textarea>
830
+ </div>
831
+ <small class="hint" id="agw-step1-hint">Name + purpose are required (or paste your own markdown).</small>
832
+ <div class="actions" style="justify-content:flex-end">
833
+ <button type="button" id="agw-start" class="btn-go" disabled>
834
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round"><path d="M5 12h14M13 6l6 6-6 6"></path></svg>
835
+ Generate agent
836
+ </button>
837
+ </div>
838
+ </div>
839
+
840
+ <!-- Step 2: live generation -->
841
+ <div class="wiz-step hidden" id="agw-step-2">
842
+ <div class="ws-loader" role="status" aria-live="polite">
843
+ <div class="spinner" aria-hidden="true"></div>
844
+ <div class="status-label" id="agw-status">Starting&hellip;</div>
845
+ </div>
846
+ <div class="actions" style="justify-content:flex-end">
847
+ <button type="button" id="agw-abort" class="btn btn-ghost btn-mini">Abort</button>
848
+ </div>
849
+ </div>
850
+
851
+ <!-- Step 3: review/edit draft (shared agent-f-* form classes) -->
852
+ <div class="wiz-step hidden" id="agw-step-3">
853
+ <div class="field"><label>Display name</label><input class="agent-f-name input" type="text" spellcheck="false" /></div>
854
+ <div class="field"><label>Description</label><input class="agent-f-desc input" type="text" spellcheck="false" /></div>
855
+ <div class="row-2">
856
+ <div class="field"><label>Color</label><div class="select-wrap"><select class="agent-f-color select"><option>green</option><option>peach</option><option>red</option><option>blue</option><option>violet</option><option>amber</option></select></div></div>
857
+ <div class="field"><label>Runner type</label><div class="select-wrap"><select class="agent-f-runner select"><option>producer</option><option>verifier</option></select></div></div>
858
+ </div>
859
+ <div class="field"><label>Consumes</label><div class="agent-f-consumes chip-select"></div></div>
860
+ <div class="field"><label>Optional consumes</label><div class="agent-f-optional chip-select"></div></div>
861
+ <div class="field"><label>Produces</label><div class="agent-f-produces chip-select"></div></div>
862
+ <div class="field"><label>Connects to</label>
863
+ <label class="fanout-toggle"><input type="checkbox" class="agent-f-connect-any" /><span>any agent (*)</span></label>
864
+ <div class="agent-f-connects chip-select"></div></div>
865
+ <div class="row-2">
866
+ <div class="field"><label>Order</label><input class="agent-f-order input" type="number" step="0.1" /></div>
867
+ <div class="field"><label>Flags</label>
868
+ <label class="fanout-toggle"><input type="checkbox" class="agent-f-fanout" /><span>Fan-out</span></label>
869
+ <label class="fanout-toggle"><input type="checkbox" class="agent-f-loopsource" /><span>Loop source</span></label>
870
+ <label class="fanout-toggle"><input type="checkbox" class="agent-f-questions" /><span>Asks questions</span></label>
871
+ <label class="fanout-toggle"><input type="checkbox" class="agent-f-questions-locked" /><span>Questions locked</span></label>
872
+ <label class="fanout-toggle"><input type="checkbox" class="agent-f-questions-default" /><span>Questions on by default</span></label></div>
873
+ </div>
874
+ <div class="field"><label>System prompt (markdown)</label>
875
+ <textarea class="agent-f-md textarea" rows="16" spellcheck="false"></textarea></div>
876
+ <p id="agw-msg" class="form-msg" aria-live="polite"></p>
877
+ <div class="actions" style="justify-content:space-between">
878
+ <button type="button" id="agw-regen" class="btn btn-ghost btn-mini">Regenerate</button>
879
+ <button type="button" id="agw-save" class="btn-go">
880
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4"><path d="M5 13l4 4L19 7" stroke-linecap="round" stroke-linejoin="round"></path></svg>
881
+ Save agent
882
+ </button>
883
+ </div>
884
+ </div>
885
+ </section>
886
+ </section>
887
+ <!-- /view agent-create -->
888
+
889
+ <!-- ===== VIEW: PIPELINE COMPOSER ===== -->
890
+ <section class="view hidden" data-view="composer">
891
+ <div class="topbar">
892
+ <div>
893
+ <h1>Pipeline Composer</h1>
894
+ <div class="sub">Compose how your agents collaborate — drag, stack, and loop them into a pipeline</div>
895
+ </div>
896
+ <button type="button" class="btn-ghost" id="composer-reset" style="padding:11px 20px">Reset to default</button>
897
+ </div>
898
+
899
+ <section class="card builder-card">
900
+ <div class="palette">
901
+ <span class="p-label">
902
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="6" cy="6" r="2"></circle><circle cx="6" cy="18" r="2"></circle><circle cx="18" cy="6" r="2"></circle><circle cx="18" cy="18" r="2"></circle></svg>
903
+ Agents · drag onto the canvas to build your pipeline
904
+ <input id="composer-agent-filter" class="pal-filter" type="search" placeholder="Filter agents…" aria-label="Filter agents by name or description">
905
+ </span>
906
+ <div id="composer-palette" style="display:contents"></div>
907
+ </div>
908
+
909
+ <div class="canvas-wrap" id="composer-canvas-wrap">
910
+ <div id="composer-decomposer-hint" class="composer-hint" hidden>
911
+ When a Decompose step is present, 1 implementer is started per task it produces — the count varies per run.
912
+ </div>
913
+ <div class="flow" id="composer-flow">
914
+ <svg class="wires" id="composer-wires"></svg>
915
+ </div>
916
+ </div>
917
+
918
+ <div class="builder-foot">
919
+ <div class="legend">
920
+ <span class="lg"><span class="ll"></span> sequential — runs in order</span>
921
+ <span class="lg"><span class="ll fb"></span> feedback loop</span>
922
+ <span class="lg"><span class="ll sl"></span> self loop</span>
923
+ </div>
924
+ <span class="link-banner" id="composer-link-banner" hidden>
925
+ <span id="composer-link-text">Click a target agent to draw a feedback loop</span>
926
+ <button type="button" id="composer-link-cancel">Cancel</button>
927
+ </span>
928
+ <span class="sp"></span>
929
+ <button type="button" class="btn-ghost" id="composer-clear" style="padding:10px 18px">Clear canvas</button>
930
+ <button type="button" class="btn-go" id="composer-save">
931
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4"><path d="M5 13l4 4L19 7" stroke-linecap="round" stroke-linejoin="round"></path></svg>
932
+ Save pipeline
933
+ </button>
934
+ </div>
935
+ </section>
936
+
937
+ <section class="card saved-card">
938
+ <div class="saved-head">
939
+ <div><b>Saved pipelines</b><span class="cnt" id="composer-saved-count"></span></div>
940
+ </div>
941
+ <div class="saved-list" id="composer-saved-list"></div>
942
+ </section>
943
+ </section>
944
+ <!-- /view composer -->
945
+
946
+ <!-- ===== VIEW: SETTINGS ===== -->
947
+ <section class="view hidden" data-view="settings">
948
+ <div class="topbar">
949
+ <div>
950
+ <h1>Settings</h1>
951
+ <div class="sub">Machine-wide Worca CC preferences</div>
952
+ </div>
953
+ </div>
954
+
955
+ <section class="card settings-card">
956
+ <div class="field">
957
+ <div class="label-row">
958
+ <label for="settingsRoot">Worca CC root folder</label>
959
+ <button type="button" class="info-tip" aria-label="About Worca CC root folder">i<span class="tip-content hidden">
960
+ The folder under which Worca CC keeps its data &mdash; a <code>.worca-cc/</code> directory holding the
961
+ history store, the project list, and saved workflows. Leave empty to use the default.
962
+ Changes apply to new runs immediately. Changing the root does <b>not</b> move existing
963
+ data: Worca CC starts a fresh <code>.worca-cc/</code> under the new folder; history under
964
+ the old root is left in place.
965
+ </span></button>
966
+ </div>
967
+ <input id="settingsRoot" class="input" type="text" placeholder="" spellcheck="false" autocomplete="off" />
968
+ </div>
969
+ <div class="field">
970
+ <div class="label-row">
971
+ <label for="settingsProjectsRoot">Projects root folder</label>
972
+ <button type="button" class="info-tip" aria-label="About Projects root folder">i<span class="tip-content hidden">
973
+ The top-level folder under which your projects live. Its CLAUDE.md, .claude/skills, and
974
+ .mcp.json are made available to every pipeline agent. Leave empty to use your home folder.
975
+ </span></button>
976
+ </div>
977
+ <div class="path-row">
978
+ <input id="settingsProjectsRoot" class="input" type="text" placeholder="" spellcheck="false" autocomplete="off" />
979
+ <button type="button" id="settingsProjectsRootBrowse" class="btn btn-ghost btn-mini" title="Pick the projects root folder">Browse&hellip;</button>
980
+ </div>
981
+ </div>
982
+ <div class="add-project-actions" style="margin-top:14px">
983
+ <button type="button" id="settingsReset" class="btn btn-ghost btn-mini">Reset to default</button>
984
+ <button type="button" id="settingsSave" class="btn btn-primary btn-mini">Save</button>
985
+ </div>
986
+ <small class="hint" id="settingsMsg"></small>
987
+ </section>
988
+
989
+ <section class="card settings-card">
990
+ <div class="card-head">
991
+ <div class="label-row">
992
+ <h2>Budget &amp; cost limits</h2>
993
+ <button type="button" class="info-tip" aria-label="About budget costs">i<span class="tip-content hidden">
994
+ Costs are Claude Code's client-side estimate (total_cost_usd), not authoritative billing.
995
+ </span></button>
996
+ </div>
997
+ </div>
998
+ <div id="budgetReadout"></div>
999
+ <div class="field">
1000
+ <div class="label-row">
1001
+ <label for="budgetPerPipeline">Per-pipeline cost limit (USD)</label>
1002
+ <button type="button" class="info-tip" aria-label="About Per-pipeline cost limit">i<span class="tip-content hidden">
1003
+ Pause a pipeline when its estimated cost reaches this amount. Leave empty for no limit.
1004
+ </span></button>
1005
+ </div>
1006
+ <input id="budgetPerPipeline" class="input" type="number" min="0" step="0.01" inputmode="decimal" placeholder="No limit" autocomplete="off" />
1007
+ </div>
1008
+ <div class="field">
1009
+ <div class="label-row">
1010
+ <label for="budgetTotal">Total cost limit (USD)</label>
1011
+ <button type="button" class="info-tip" aria-label="About Total cost limit">i<span class="tip-content hidden">
1012
+ Pause all pipelines and block new ones when total spend in the period reaches this amount.
1013
+ Leave empty for no limit.
1014
+ </span></button>
1015
+ </div>
1016
+ <input id="budgetTotal" class="input" type="number" min="0" step="0.01" inputmode="decimal" placeholder="No limit" autocomplete="off" />
1017
+ </div>
1018
+ <div class="field">
1019
+ <div class="label-row">
1020
+ <label for="budgetResetPeriod">Reset period</label>
1021
+ <button type="button" class="info-tip" aria-label="About Reset period">i<span class="tip-content hidden">
1022
+ Spend counts within the current period and returns to $0.00 at the reset. Times are local.
1023
+ </span></button>
1024
+ </div>
1025
+ <div class="select-wrap">
1026
+ <select id="budgetResetPeriod" class="select">
1027
+ <option value="weekly">Weekly &mdash; resets Monday 00:00</option>
1028
+ <option value="monthly">Monthly &mdash; resets on the 1st, 00:00</option>
1029
+ </select>
1030
+ </div>
1031
+ </div>
1032
+ <div class="add-project-actions" style="margin-top:14px">
1033
+ <button type="button" id="budgetReset" class="btn btn-ghost btn-mini">Clear limits</button>
1034
+ <button type="button" id="budgetSave" class="btn btn-primary btn-mini">Save</button>
1035
+ </div>
1036
+ <small class="hint" id="budgetMsg"></small>
1037
+ </section>
1038
+
1039
+ <!-- Chat notifications (chat-connectivity-design.md §4.8): which run
1040
+ events ping which chat channels. Body rendered by
1041
+ chat-settings-view.mjs; app.js owns fetch/save/Test wiring. -->
1042
+ <section class="card settings-card" id="chat-settings-card">
1043
+ <div class="label-row">
1044
+ <h2>Chat notifications</h2>
1045
+ </div>
1046
+ <div id="chat-settings-host"></div>
1047
+ <div class="add-project-actions" style="margin-top:14px">
1048
+ <button id="chatSettingsSave" class="btn btn-primary btn-mini" type="button">Save</button>
1049
+ </div>
1050
+ <small class="hint" id="chatSettingsMsg"></small>
1051
+ </section>
1052
+ </section>
1053
+ <!-- /view settings -->
1054
+ </main>
1055
+ </div>
1056
+
1057
+ <!-- ===== Saved-markdown viewer (modal) ===== -->
1058
+ <div id="viewer-card" class="viewer-modal hidden">
1059
+ <div class="card">
1060
+ <div class="card-head">
1061
+ <h2 id="viewer-title">Saved pipeline</h2>
1062
+ <button type="button" id="viewer-close" class="btn btn-mini">Close</button>
1063
+ </div>
1064
+ <pre id="viewer" class="viewer"></pre>
1065
+ </div>
1066
+ </div>
1067
+
1068
+ <!-- ===== Folder browser (fallback when no native dialog) ===== -->
1069
+ <div id="folder-browser" class="viewer-modal folder-modal hidden">
1070
+ <div class="card">
1071
+ <div class="card-head">
1072
+ <h2>Select a folder</h2>
1073
+ <button type="button" id="folderBrowserClose" class="btn btn-mini">Close</button>
1074
+ </div>
1075
+ <div class="folder-toolbar">
1076
+ <button type="button" id="folderUp" class="btn btn-ghost btn-mini" title="Parent folder">&#8593; Up</button>
1077
+ <button type="button" id="folderHome" class="btn btn-ghost btn-mini" title="Home folder">Home</button>
1078
+ <code id="folderCurrent" class="folder-current"></code>
1079
+ </div>
1080
+ <ul id="folderList" class="folder-list"></ul>
1081
+ <div class="add-project-actions">
1082
+ <button type="button" id="folderSelect" class="btn btn-primary btn-mini">Select this folder</button>
1083
+ </div>
1084
+ <small class="hint" id="folderMsg"></small>
1085
+ </div>
1086
+ </div>
1087
+
1088
+ <!-- ===== Reusable confirmation modal ===== -->
1089
+ <div id="confirm-modal" class="viewer-modal confirm-modal hidden" role="dialog" aria-modal="true" aria-labelledby="confirm-title">
1090
+ <div class="card">
1091
+ <div class="card-head">
1092
+ <h2 id="confirm-title">Confirm</h2>
1093
+ </div>
1094
+ <p id="confirm-message" class="confirm-message"></p>
1095
+ <label id="confirm-checkbox-wrap" class="confirm-checkbox hidden">
1096
+ <input type="checkbox" id="confirm-checkbox" />
1097
+ <span id="confirm-checkbox-label"></span>
1098
+ </label>
1099
+ <div class="confirm-actions">
1100
+ <button type="button" id="confirm-cancel" class="btn btn-ghost btn-mini">Cancel</button>
1101
+ <button type="button" id="confirm-ok" class="btn btn-primary btn-mini">Confirm</button>
1102
+ </div>
1103
+ </div>
1104
+ </div>
1105
+
1106
+ <!-- ===== Add-project modal ===== -->
1107
+ <div id="project-add-modal" class="viewer-modal confirm-modal hidden" role="dialog" aria-modal="true" aria-labelledby="proj-add-title">
1108
+ <div class="card">
1109
+ <div class="card-head">
1110
+ <h2 id="proj-add-title">Add project</h2>
1111
+ <button type="button" id="proj-add-cancel" class="btn btn-mini">Close</button>
1112
+ </div>
1113
+ <div class="field">
1114
+ <label for="proj-add-name">Name</label>
1115
+ <input id="proj-add-name" class="input" type="text" spellcheck="false" placeholder="Project name" />
1116
+ </div>
1117
+ <div class="field">
1118
+ <label for="proj-add-path">Folder</label>
1119
+ <div class="path-row">
1120
+ <input id="proj-add-path" class="input" type="text" spellcheck="false" placeholder="/absolute/path/to/project" />
1121
+ <button type="button" id="proj-add-browse" class="btn btn-ghost btn-mini" title="Pick the project folder">Choose folder&hellip;</button>
1122
+ </div>
1123
+ </div>
1124
+ <small class="hint" id="proj-add-msg"></small>
1125
+ <div class="confirm-actions">
1126
+ <button type="button" id="proj-add-save" class="btn btn-primary btn-mini">Add project</button>
1127
+ </div>
1128
+ </div>
1129
+ </div>
1130
+
1131
+ <!-- ===== Plugin modal (install consent / update preview / settings / doctor / 409) ===== -->
1132
+ <div id="plugin-modal" class="viewer-modal hidden" role="dialog" aria-modal="true" aria-labelledby="plugin-modal-title">
1133
+ <div class="card">
1134
+ <div class="card-head">
1135
+ <h2 id="plugin-modal-title">Plugin</h2>
1136
+ <button type="button" id="plugin-modal-close" class="btn btn-mini">Close</button>
1137
+ </div>
1138
+ <div id="plugin-modal-body"></div>
1139
+ <div class="confirm-actions" id="plugin-modal-actions"></div>
1140
+ </div>
1141
+ </div>
1142
+
1143
+ <script src="/app.js" type="module"></script>
1144
+ </body>
1145
+ </html>