@mobrienv/autoloop 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +100 -29
- package/dist/backend/acp-client.js +6 -1
- package/dist/backend/acp-client.js.map +1 -1
- package/dist/backend/kiro-bridge.d.ts +2 -0
- package/dist/backend/kiro-bridge.js +32 -2
- package/dist/backend/kiro-bridge.js.map +1 -1
- package/dist/backend/kiro-worker.js +7 -3
- package/dist/backend/kiro-worker.js.map +1 -1
- package/dist/cli/color.d.ts +6 -0
- package/dist/cli/color.js +40 -0
- package/dist/cli/color.js.map +1 -0
- package/dist/commands/inspect.js +45 -5
- package/dist/commands/inspect.js.map +1 -1
- package/dist/config.js +1 -1
- package/dist/config.js.map +1 -1
- package/dist/dashboard/app.js +1 -1
- package/dist/dashboard/app.js.map +1 -1
- package/dist/dashboard/routes/api.js +56 -0
- package/dist/dashboard/routes/api.js.map +1 -1
- package/dist/dashboard/routes/pages.d.ts +1 -1
- package/dist/dashboard/routes/pages.js +4 -2
- package/dist/dashboard/routes/pages.js.map +1 -1
- package/dist/dashboard/views/shell.d.ts +1 -1
- package/dist/dashboard/views/shell.js +339 -23
- package/dist/dashboard/views/shell.js.map +1 -1
- package/dist/events/types.d.ts +2 -1
- package/dist/harness/artifacts.d.ts +50 -0
- package/dist/harness/artifacts.js +333 -0
- package/dist/harness/artifacts.js.map +1 -0
- package/dist/harness/config-helpers.js +3 -5
- package/dist/harness/config-helpers.js.map +1 -1
- package/dist/harness/index.d.ts +7 -0
- package/dist/harness/index.js +78 -7
- package/dist/harness/index.js.map +1 -1
- package/dist/harness/journal-format.d.ts +25 -0
- package/dist/harness/journal-format.js +153 -0
- package/dist/harness/journal-format.js.map +1 -0
- package/dist/loops/health.d.ts +1 -0
- package/dist/loops/health.js +1 -1
- package/dist/loops/health.js.map +1 -1
- package/dist/usage.js +4 -3
- package/dist/usage.js.map +1 -1
- package/dist/worktree/clean.js +18 -3
- package/dist/worktree/clean.js.map +1 -1
- package/package.json +19 -4
- package/plugins/autoloop/.claude-plugin/plugin.json +1 -1
- package/presets/autodebug/README.md +50 -0
- package/presets/autodebug/autoloops.toml +18 -0
- package/presets/autodebug/harness.md +31 -0
- package/presets/autodebug/roles/fixer.md +58 -0
- package/presets/autodebug/roles/investigator.md +52 -0
- package/presets/autodebug/roles/strategist.md +45 -0
- package/presets/autodebug/roles/verifier.md +66 -0
- package/presets/autodebug/topology.toml +34 -0
- package/presets/autopreset/README.md +35 -0
- package/presets/autopreset/autoloops.toml +18 -0
- package/presets/autopreset/harness.md +38 -0
- package/presets/autopreset/roles/designer.md +33 -0
- package/presets/autopreset/roles/finalizer.md +23 -0
- package/presets/autopreset/roles/generator.md +34 -0
- package/presets/autopreset/roles/validator.md +31 -0
- package/presets/autopreset/topology.toml +32 -0
- package/presets/autoqa/README.md +43 -14
- package/presets/autoqa/autoloops.toml +2 -2
- package/presets/autoqa/harness.md +30 -8
- package/presets/autoqa/roles/executor.md +64 -11
- package/presets/autoqa/roles/inspector.md +68 -13
- package/presets/autoqa/roles/planner.md +43 -11
- package/presets/autoqa/roles/reporter.md +51 -8
|
@@ -1,16 +1,20 @@
|
|
|
1
|
-
export function htmlShell() {
|
|
1
|
+
export function htmlShell(projectName) {
|
|
2
|
+
const displayName = projectName || "autoloop";
|
|
2
3
|
return `<!DOCTYPE html>
|
|
3
4
|
<html lang="en">
|
|
4
5
|
<head>
|
|
5
6
|
<meta charset="utf-8">
|
|
6
7
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
7
|
-
<title>autoloop
|
|
8
|
+
<title>autoloop / ${displayName}</title>
|
|
8
9
|
<style>
|
|
9
10
|
:root {
|
|
10
11
|
--bg: #fff; --fg: #1a1a1a; --muted: #666; --border: #e0e0e0;
|
|
11
12
|
--card-bg: #fafafa; --badge-bg: #eee;
|
|
12
13
|
--active: #2563eb; --watching: #d97706; --stuck: #dc2626;
|
|
13
14
|
--failed: #dc2626; --completed: #16a34a;
|
|
15
|
+
--cat-loop: #06b6d4; --cat-iteration: #d97706; --cat-backend: #666;
|
|
16
|
+
--cat-review: #c026d3; --cat-coordination: #2563eb; --cat-error: #dc2626;
|
|
17
|
+
--cat-operator: #ef4444; --cat-completion: #16a34a;
|
|
14
18
|
}
|
|
15
19
|
@media (prefers-color-scheme: dark) {
|
|
16
20
|
:root {
|
|
@@ -109,12 +113,43 @@ header .updated { font-size: 0.75rem; color: var(--muted); font-family: monospac
|
|
|
109
113
|
.merged-badge { color: var(--completed); font-weight: 600; }
|
|
110
114
|
.merge-detail { margin-top: 0.5rem; padding: 0.5rem; background: color-mix(in srgb, var(--completed) 8%, transparent); border: 1px solid color-mix(in srgb, var(--completed) 25%, transparent); border-radius: 4px; }
|
|
111
115
|
.merge-detail .field label { color: var(--completed); }
|
|
116
|
+
|
|
117
|
+
.detail-tabs { display: flex; gap: 0; border-bottom: 2px solid var(--border); margin-top: 0.75rem; margin-bottom: 0; }
|
|
118
|
+
.detail-tab { background: none; border: none; padding: 0.4rem 0.8rem; font-size: 0.8rem; font-family: monospace; cursor: pointer; color: var(--muted); border-bottom: 2px solid transparent; margin-bottom: -2px; }
|
|
119
|
+
.detail-tab:hover { color: var(--fg); }
|
|
120
|
+
.detail-tab.active { color: var(--active); border-bottom-color: var(--active); font-weight: 600; }
|
|
121
|
+
|
|
122
|
+
.topic-chip { display: inline-flex; align-items: center; gap: 0.2rem; padding: 0.15rem 0.4rem; border: 1px solid var(--border); border-left-width: 3px; border-radius: 4px; background: none; font-size: 0.7rem; font-family: monospace; cursor: pointer; color: var(--muted); }
|
|
123
|
+
.topic-chip.active { color: var(--fg); background: var(--card-bg); }
|
|
124
|
+
.topic-chip .badge { font-size: 0.6rem; padding: 0 0.25rem; }
|
|
125
|
+
|
|
126
|
+
.journal-search { width: 100%; padding: 0.35rem 0.5rem; border: 1px solid var(--border); border-radius: 4px; font-size: 0.8rem; font-family: inherit; background: var(--bg); color: var(--fg); }
|
|
127
|
+
|
|
128
|
+
.iter-group { border: 1px solid var(--border); border-radius: 4px; margin-bottom: 0.4rem; }
|
|
129
|
+
.iter-group > summary { cursor: pointer; padding: 0.3rem 0.5rem; font-size: 0.75rem; font-family: monospace; color: var(--muted); background: var(--card-bg); list-style: none; }
|
|
130
|
+
.iter-group > summary::-webkit-details-marker { display: none; }
|
|
131
|
+
.iter-group > summary::before { content: "\\25b6 "; font-size: 0.6rem; }
|
|
132
|
+
.iter-group[open] > summary::before { content: "\\25bc "; }
|
|
133
|
+
|
|
134
|
+
.artifacts-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 0.5rem; margin-bottom: 0.75rem; }
|
|
135
|
+
.artifact-stat-card { background: var(--bg); border: 1px solid var(--border); border-radius: 6px; padding: 0.5rem; text-align: center; }
|
|
136
|
+
.artifact-stat-value { font-size: 1.2rem; font-weight: 700; font-family: monospace; }
|
|
137
|
+
.artifact-stat-label { font-size: 0.7rem; color: var(--muted); }
|
|
138
|
+
.artifacts-bar-chart { margin: 0.5rem 0; }
|
|
139
|
+
.bar-row { display: grid; grid-template-columns: 80px 1fr 40px; gap: 0.4rem; align-items: center; font-size: 0.75rem; margin-bottom: 0.2rem; }
|
|
140
|
+
.bar-label { text-align: right; color: var(--muted); font-family: monospace; }
|
|
141
|
+
.bar-track { height: 14px; background: var(--badge-bg); border-radius: 3px; overflow: hidden; }
|
|
142
|
+
.bar-fill { height: 100%; border-radius: 3px; min-width: 2px; }
|
|
143
|
+
.bar-count { font-family: monospace; text-align: right; }
|
|
144
|
+
.artifact-doc-row { display: flex; align-items: center; gap: 0.5rem; padding: 0.3rem 0; border-bottom: 1px solid var(--border); font-size: 0.8rem; }
|
|
145
|
+
.artifact-view-btn { padding: 0.15rem 0.5rem; border: 1px solid var(--border); border-radius: 3px; background: var(--bg); color: var(--fg); cursor: pointer; font-size: 0.7rem; }
|
|
146
|
+
.artifact-view-btn:hover { background: var(--badge-bg); }
|
|
112
147
|
</style>
|
|
113
148
|
</head>
|
|
114
149
|
<body x-data="dashboard()" x-init="startPolling()">
|
|
115
150
|
|
|
116
151
|
<header>
|
|
117
|
-
<h1>autoloop
|
|
152
|
+
<h1>autoloop <span style="color:var(--muted);font-weight:400">/ ${displayName}</span></h1>
|
|
118
153
|
<span class="updated" x-text="lastUpdated ? 'updated ' + lastUpdated : 'loading...'"></span>
|
|
119
154
|
</header>
|
|
120
155
|
|
|
@@ -132,7 +167,7 @@ header .updated { font-size: 0.75rem; color: var(--muted); font-family: monospac
|
|
|
132
167
|
<details class="section" :open="sectionOpen[cat.key]" @toggle="sectionUserToggled[cat.key] = true; sectionOpen[cat.key] = $el.open">
|
|
133
168
|
<summary>
|
|
134
169
|
<span x-text="cat.label"></span>
|
|
135
|
-
<span class="badge" :data-status="cat.key" x-text="cat.
|
|
170
|
+
<span class="badge" :data-status="cat.key" x-text="cat.total"></span>
|
|
136
171
|
</summary>
|
|
137
172
|
<ul class="run-list">
|
|
138
173
|
<template x-for="run in cat.items" :key="run.run_id">
|
|
@@ -160,6 +195,12 @@ header .updated { font-size: 0.75rem; color: var(--muted); font-family: monospac
|
|
|
160
195
|
</li>
|
|
161
196
|
</template>
|
|
162
197
|
<li class="empty" x-show="cat.items.length === 0">None</li>
|
|
198
|
+
<li x-show="cat.capped" style="text-align:center;padding:0.3rem;list-style:none">
|
|
199
|
+
<button @click="sectionShowAll[cat.key] = true" style="background:none;border:1px solid var(--border);border-radius:4px;padding:0.25rem 0.6rem;color:var(--muted);cursor:pointer;font-size:0.75rem" x-text="'Show all ' + cat.total + ' runs'"></button>
|
|
200
|
+
</li>
|
|
201
|
+
<li x-show="sectionShowAll[cat.key] && cat.total > 10" style="text-align:center;padding:0.3rem;list-style:none">
|
|
202
|
+
<button @click="sectionShowAll[cat.key] = false" style="background:none;border:1px solid var(--border);border-radius:4px;padding:0.25rem 0.6rem;color:var(--muted);cursor:pointer;font-size:0.75rem">Show fewer</button>
|
|
203
|
+
</li>
|
|
163
204
|
</ul>
|
|
164
205
|
</details>
|
|
165
206
|
</template>
|
|
@@ -170,7 +211,7 @@ header .updated { font-size: 0.75rem; color: var(--muted); font-family: monospac
|
|
|
170
211
|
<div>
|
|
171
212
|
<div class="field"><label>Status: </label><span x-text="selectedRunDetail.status"></span></div>
|
|
172
213
|
<div class="field"><label>Preset: </label><span x-text="selectedRunDetail.preset"></span></div>
|
|
173
|
-
<div class="field"><label>Objective: </label><
|
|
214
|
+
<div class="field"><label>Objective: </label><div class="md-content" style="display:inline" x-html="renderMarkdown(selectedRunDetail.objective)"></div></div>
|
|
174
215
|
<div class="field"><label>Iteration: </label><span x-text="selectedRunDetail.iteration + '/' + (selectedRunDetail.max_iterations || '?')"></span></div>
|
|
175
216
|
<div class="field"><label>Workspace: </label><span :title="workspacePath(selectedRunDetail)" x-text="workspaceLabel(selectedRunDetail)"></span></div>
|
|
176
217
|
<div class="field"><label>Created: </label><span :title="selectedRunDetail.created_at" x-text="timeAgo(selectedRunDetail.created_at) + ' ago'"></span></div>
|
|
@@ -187,7 +228,20 @@ header .updated { font-size: 0.75rem; color: var(--muted); font-family: monospac
|
|
|
187
228
|
</template>
|
|
188
229
|
</div>
|
|
189
230
|
</template>
|
|
190
|
-
<div
|
|
231
|
+
<div x-show="selectedRunDetail && selectedRunDetail.status === 'running'" style="display:grid;grid-template-columns:1fr auto;gap:0.4rem;align-items:center;margin:0.75rem 0;padding:0.6rem;border:1px solid var(--border);border-radius:6px;background:var(--bg)">
|
|
232
|
+
<input type="text" x-model="guideMessage" placeholder="Send guidance to this run..." @keydown.enter="sendGuide()"
|
|
233
|
+
style="width:100%;box-sizing:border-box;padding:0.4rem 0.6rem;border:1px solid var(--border);border-radius:4px;font-size:0.8rem;font-family:inherit;background:var(--bg);color:var(--fg)">
|
|
234
|
+
<div style="display:flex;gap:0.4rem;align-items:center">
|
|
235
|
+
<button @click="sendGuide()" style="padding:0.4rem 0.8rem;border:none;border-radius:4px;background:var(--active);color:#fff;cursor:pointer;font-size:0.8rem;white-space:nowrap">Send</button>
|
|
236
|
+
<span x-show="guideFlash" x-text="guideFlash" x-transition.opacity style="font-size:0.75rem;color:var(--completed)"></span>
|
|
237
|
+
</div>
|
|
238
|
+
</div>
|
|
239
|
+
<div class="detail-tabs" x-show="selectedRunDetail">
|
|
240
|
+
<button class="detail-tab" :class="{ active: detailTab === 'events' }" @click="detailTab = 'events'">Events</button>
|
|
241
|
+
<button class="detail-tab" :class="{ active: detailTab === 'journal' }" @click="detailTab = 'journal'">Journal</button>
|
|
242
|
+
<button class="detail-tab" :class="{ active: detailTab === 'artifacts' }" @click="detailTab = 'artifacts'">Artifacts</button>
|
|
243
|
+
</div>
|
|
244
|
+
<div x-show="detailTab === 'events'" class="events-list">
|
|
191
245
|
<div style="display:flex;justify-content:space-between;align-items:center">
|
|
192
246
|
<h3>Events</h3>
|
|
193
247
|
<label style="font-size:0.75rem;cursor:pointer"><input type="checkbox" x-model="showVerbose" style="margin-right:0.3rem">Show backend events</label>
|
|
@@ -302,11 +356,132 @@ header .updated { font-size: 0.75rem; color: var(--muted); font-family: monospac
|
|
|
302
356
|
</template>
|
|
303
357
|
<p class="empty" x-show="visibleRunEvents().length === 0">No events</p>
|
|
304
358
|
</div>
|
|
305
|
-
<div x-show="
|
|
306
|
-
<
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
<
|
|
359
|
+
<div x-show="detailTab === 'journal'" class="events-list">
|
|
360
|
+
<div style="margin-bottom:0.5rem">
|
|
361
|
+
<input type="text" class="journal-search" x-model="journalSearch" placeholder="Search events...">
|
|
362
|
+
</div>
|
|
363
|
+
<div style="display:flex;flex-wrap:wrap;gap:0.3rem;margin-bottom:0.5rem">
|
|
364
|
+
<template x-for="cat in journalCategoryChips()" :key="cat.key">
|
|
365
|
+
<button class="topic-chip" :class="{ active: journalCategoryFilter[cat.key] }" :style="'border-color:' + cat.color" @click="journalCategoryFilter[cat.key] = !journalCategoryFilter[cat.key]">
|
|
366
|
+
<span x-text="cat.label"></span>
|
|
367
|
+
<span class="badge" x-text="cat.count"></span>
|
|
368
|
+
</button>
|
|
369
|
+
</template>
|
|
370
|
+
</div>
|
|
371
|
+
<template x-for="group in journalGroups()" :key="group.key">
|
|
372
|
+
<details class="iter-group" open>
|
|
373
|
+
<summary x-text="group.label + ' (' + group.events.length + ' events)'"></summary>
|
|
374
|
+
<template x-for="(ev, idx) in group.events" :key="idx">
|
|
375
|
+
<details :class="eventClasses(ev)">
|
|
376
|
+
<summary x-text="eventSummary(ev)"></summary>
|
|
377
|
+
<div style="padding:0.3rem">
|
|
378
|
+
<template x-for="[k,v] in eventDisplayEntries(ev)" :key="k">
|
|
379
|
+
<div class="event-field">
|
|
380
|
+
<strong x-text="k + ':'"></strong>
|
|
381
|
+
<template x-if="isRoutingBadgeField(k)">
|
|
382
|
+
<span x-html="renderRoutingValue(k, v)"></span>
|
|
383
|
+
</template>
|
|
384
|
+
<template x-if="!isRoutingBadgeField(k) && isMarkdownField(ev.topic, k)">
|
|
385
|
+
<template x-if="String(typeof v === 'object' ? JSON.stringify(v,null,2) : v).length <= 200">
|
|
386
|
+
<div class="md-content" x-html="renderMarkdown(typeof v === 'object' ? JSON.stringify(v,null,2) : String(v))"></div>
|
|
387
|
+
</template>
|
|
388
|
+
</template>
|
|
389
|
+
<template x-if="!isRoutingBadgeField(k) && isMarkdownField(ev.topic, k)">
|
|
390
|
+
<template x-if="String(typeof v === 'object' ? JSON.stringify(v,null,2) : v).length > 200">
|
|
391
|
+
<details>
|
|
392
|
+
<summary x-text="k + ' (' + String(typeof v === 'object' ? JSON.stringify(v,null,2) : v).length + ' chars)'"></summary>
|
|
393
|
+
<div class="md-content" style="font-size:0.7rem;margin-top:0.2rem" x-html="renderMarkdown(typeof v === 'object' ? JSON.stringify(v,null,2) : String(v))"></div>
|
|
394
|
+
</details>
|
|
395
|
+
</template>
|
|
396
|
+
</template>
|
|
397
|
+
<template x-if="!isRoutingBadgeField(k) && !isMarkdownField(ev.topic, k)">
|
|
398
|
+
<template x-if="String(typeof v === 'object' ? JSON.stringify(v,null,2) : v).length <= 200">
|
|
399
|
+
<pre x-text="typeof v === 'object' ? JSON.stringify(v,null,2) : String(v)"></pre>
|
|
400
|
+
</template>
|
|
401
|
+
</template>
|
|
402
|
+
<template x-if="!isRoutingBadgeField(k) && !isMarkdownField(ev.topic, k)">
|
|
403
|
+
<template x-if="String(typeof v === 'object' ? JSON.stringify(v,null,2) : v).length > 200">
|
|
404
|
+
<details>
|
|
405
|
+
<summary x-text="k + ' (' + String(typeof v === 'object' ? JSON.stringify(v,null,2) : v).length + ' chars)'"></summary>
|
|
406
|
+
<pre style="white-space:pre-wrap;font-size:0.7rem;margin-top:0.2rem" x-text="typeof v === 'object' ? JSON.stringify(v,null,2) : String(v)"></pre>
|
|
407
|
+
</details>
|
|
408
|
+
</template>
|
|
409
|
+
</template>
|
|
410
|
+
</div>
|
|
411
|
+
</template>
|
|
412
|
+
</div>
|
|
413
|
+
</details>
|
|
414
|
+
</template>
|
|
415
|
+
</details>
|
|
416
|
+
</template>
|
|
417
|
+
<p class="empty" x-show="journalGroups().length === 0">No matching events</p>
|
|
418
|
+
</div>
|
|
419
|
+
<div x-show="detailTab === 'artifacts'" class="events-list">
|
|
420
|
+
<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:0.75rem">
|
|
421
|
+
<h3 style="font-size:0.95rem">Artifacts</h3>
|
|
422
|
+
<button @click="fetchArtifacts()" style="padding:0.2rem 0.6rem;border:1px solid var(--border);border-radius:4px;background:var(--bg);color:var(--fg);cursor:pointer;font-size:0.75rem">Refresh</button>
|
|
423
|
+
</div>
|
|
424
|
+
|
|
425
|
+
<div x-show="artifactsData" class="artifacts-grid">
|
|
426
|
+
<div class="artifact-stat-card">
|
|
427
|
+
<div class="artifact-stat-value" x-text="artifactsData?.events?.total || 0"></div>
|
|
428
|
+
<div class="artifact-stat-label">Events</div>
|
|
429
|
+
</div>
|
|
430
|
+
<div class="artifact-stat-card">
|
|
431
|
+
<div class="artifact-stat-value" x-text="artifactsData?.iterations || 0"></div>
|
|
432
|
+
<div class="artifact-stat-label">Iterations</div>
|
|
433
|
+
</div>
|
|
434
|
+
<div class="artifact-stat-card">
|
|
435
|
+
<div class="artifact-stat-value" x-text="(artifactsData?.artifacts?.memoryLearnings || 0) + (artifactsData?.artifacts?.memoryMeta || 0)"></div>
|
|
436
|
+
<div class="artifact-stat-label">Memory</div>
|
|
437
|
+
</div>
|
|
438
|
+
<div class="artifact-stat-card">
|
|
439
|
+
<div class="artifact-stat-value" x-text="artifactsData?.artifacts?.guidanceSent || 0"></div>
|
|
440
|
+
<div class="artifact-stat-label">Guidance</div>
|
|
441
|
+
</div>
|
|
442
|
+
</div>
|
|
443
|
+
|
|
444
|
+
<div x-show="artifactsData" class="artifacts-bar-chart">
|
|
445
|
+
<template x-for="cat in artifactsCategoryBars()" :key="cat.key">
|
|
446
|
+
<div class="bar-row">
|
|
447
|
+
<span class="bar-label" x-text="cat.label"></span>
|
|
448
|
+
<div class="bar-track">
|
|
449
|
+
<div class="bar-fill" :style="'width:' + cat.pct + '%;background:' + cat.color"></div>
|
|
450
|
+
</div>
|
|
451
|
+
<span class="bar-count" x-text="cat.count"></span>
|
|
452
|
+
</div>
|
|
453
|
+
</template>
|
|
454
|
+
</div>
|
|
455
|
+
|
|
456
|
+
<div x-show="artifactsData" style="font-size:0.8rem;font-family:monospace;margin:0.75rem 0">
|
|
457
|
+
<div>commits: <span x-text="artifactsData?.output?.commits || 0"></span></div>
|
|
458
|
+
<div>files changed: <span x-text="artifactsData?.output?.filesChanged < 0 ? '-' : artifactsData?.output?.filesChanged"></span></div>
|
|
459
|
+
<div>journal size: <span x-text="formatBytes(artifactsData?.output?.journalSizeBytes || 0)"></span></div>
|
|
460
|
+
<div>backpressure: <span x-text="artifactsData?.artifacts?.backpressure || 0"></span> rejected</div>
|
|
461
|
+
</div>
|
|
462
|
+
|
|
463
|
+
<div x-show="artifactsData && artifactsData.documents && artifactsData.documents.length > 0">
|
|
464
|
+
<h4 style="font-size:0.85rem;margin:0.75rem 0 0.5rem">Documents</h4>
|
|
465
|
+
<template x-for="doc in artifactsData?.documents || []" :key="doc.path">
|
|
466
|
+
<div class="artifact-doc-row">
|
|
467
|
+
<span x-text="doc.title || doc.path"></span>
|
|
468
|
+
<span class="badge" x-text="doc.kind"></span>
|
|
469
|
+
<template x-if="doc.missing">
|
|
470
|
+
<span style="color:var(--failed);font-size:0.7rem">(missing)</span>
|
|
471
|
+
</template>
|
|
472
|
+
<template x-if="!doc.missing">
|
|
473
|
+
<button class="artifact-view-btn" @click="viewArtifactDoc(doc.path)">View</button>
|
|
474
|
+
</template>
|
|
475
|
+
</div>
|
|
476
|
+
</template>
|
|
477
|
+
</div>
|
|
478
|
+
|
|
479
|
+
<div x-show="artifactDocContent !== null" style="margin-top:0.75rem">
|
|
480
|
+
<button @click="artifactDocContent = null; artifactDocPath = ''" style="padding:0.2rem 0.6rem;border:1px solid var(--border);border-radius:4px;background:var(--bg);color:var(--fg);cursor:pointer;font-size:0.75rem;margin-bottom:0.5rem">\u2190 Back</button>
|
|
481
|
+
<div class="md-content" x-html="renderMarkdown(artifactDocContent || '')"></div>
|
|
482
|
+
</div>
|
|
483
|
+
|
|
484
|
+
<p class="empty" x-show="!artifactsData">Click Refresh to load artifacts</p>
|
|
310
485
|
</div>
|
|
311
486
|
</div>
|
|
312
487
|
|
|
@@ -325,17 +500,51 @@ function dashboard() {
|
|
|
325
500
|
lastUpdated: null,
|
|
326
501
|
sectionOpen: { active: false, watching: false, stuck: false, failed: false, completed: false },
|
|
327
502
|
sectionUserToggled: {},
|
|
503
|
+
sectionShowAll: {},
|
|
328
504
|
showVerbose: false,
|
|
329
505
|
guideMessage: "",
|
|
330
506
|
guideFlash: "",
|
|
507
|
+
artifactsData: null,
|
|
508
|
+
artifactDocContent: null,
|
|
509
|
+
artifactDocPath: '',
|
|
510
|
+
detailTab: 'events',
|
|
511
|
+
journalSearch: '',
|
|
512
|
+
journalCategoryFilter: {
|
|
513
|
+
loop: true,
|
|
514
|
+
iteration: true,
|
|
515
|
+
backend: false,
|
|
516
|
+
review: true,
|
|
517
|
+
coordination: true,
|
|
518
|
+
error: true,
|
|
519
|
+
operator: true,
|
|
520
|
+
completion: true,
|
|
521
|
+
},
|
|
522
|
+
categoryColors: {
|
|
523
|
+
loop: '#06b6d4',
|
|
524
|
+
iteration: '#d97706',
|
|
525
|
+
backend: '#666',
|
|
526
|
+
review: '#c026d3',
|
|
527
|
+
coordination: '#2563eb',
|
|
528
|
+
error: '#dc2626',
|
|
529
|
+
operator: '#ef4444',
|
|
530
|
+
completion: '#16a34a',
|
|
531
|
+
},
|
|
331
532
|
|
|
332
533
|
get categories() {
|
|
534
|
+
const CAP = 10;
|
|
535
|
+
const cap = (key, items) => {
|
|
536
|
+
const total = items.length;
|
|
537
|
+
const show = this.sectionShowAll[key] ? items : items.slice(0, CAP);
|
|
538
|
+
return { items: show, total, capped: total > CAP && !this.sectionShowAll[key] };
|
|
539
|
+
};
|
|
540
|
+
const fc = cap("failed", this.runs.recentFailed);
|
|
541
|
+
const cc = cap("completed", this.runs.recentCompleted);
|
|
333
542
|
return [
|
|
334
|
-
{ key: "active", label: "Active", items: this.runs.active },
|
|
335
|
-
{ key: "watching", label: "Watching", items: this.runs.watching },
|
|
336
|
-
{ key: "stuck", label: "Stuck", items: this.runs.stuck },
|
|
337
|
-
{ key: "failed", label: "Failed", items:
|
|
338
|
-
{ key: "completed", label: "Completed", items:
|
|
543
|
+
{ key: "active", label: "Active", items: this.runs.active, total: this.runs.active.length, capped: false },
|
|
544
|
+
{ key: "watching", label: "Watching", items: this.runs.watching, total: this.runs.watching.length, capped: false },
|
|
545
|
+
{ key: "stuck", label: "Stuck", items: this.runs.stuck, total: this.runs.stuck.length, capped: false },
|
|
546
|
+
{ key: "failed", label: "Failed", items: fc.items, total: fc.total, capped: fc.capped },
|
|
547
|
+
{ key: "completed", label: "Completed", items: cc.items, total: cc.total, capped: cc.capped },
|
|
339
548
|
];
|
|
340
549
|
},
|
|
341
550
|
|
|
@@ -348,7 +557,12 @@ function dashboard() {
|
|
|
348
557
|
async fetchRuns() {
|
|
349
558
|
try {
|
|
350
559
|
const res = await fetch("/api/runs");
|
|
351
|
-
|
|
560
|
+
const data = await res.json();
|
|
561
|
+
const byRecent = (a, b) => new Date(b.updated_at || 0) - new Date(a.updated_at || 0);
|
|
562
|
+
for (const key of ['active', 'watching', 'stuck', 'recentFailed', 'recentCompleted']) {
|
|
563
|
+
if (data[key]) data[key].sort(byRecent);
|
|
564
|
+
}
|
|
565
|
+
this.runs = data;
|
|
352
566
|
this.lastUpdated = new Date().toLocaleTimeString();
|
|
353
567
|
const defaultOpen = ['active', 'watching', 'stuck'];
|
|
354
568
|
for (const cat of this.categories) {
|
|
@@ -373,6 +587,9 @@ function dashboard() {
|
|
|
373
587
|
|
|
374
588
|
async selectRun(runId) {
|
|
375
589
|
this.selectedRun = runId;
|
|
590
|
+
this.artifactsData = null;
|
|
591
|
+
this.artifactDocContent = null;
|
|
592
|
+
this.artifactDocPath = '';
|
|
376
593
|
try {
|
|
377
594
|
const detailRes = await fetch("/api/runs/" + runId);
|
|
378
595
|
if (detailRes.ok) this.selectedRunDetail = await detailRes.json();
|
|
@@ -539,17 +756,14 @@ function dashboard() {
|
|
|
539
756
|
},
|
|
540
757
|
|
|
541
758
|
eventDisplayEntries(ev) {
|
|
542
|
-
if (ev.
|
|
759
|
+
if (ev.fields && typeof ev.fields === 'object') {
|
|
543
760
|
const entries = [];
|
|
544
761
|
for (const [k, v] of Object.entries(ev)) {
|
|
545
762
|
if (k === 'fields') continue;
|
|
546
763
|
entries.push([k, v]);
|
|
547
764
|
}
|
|
548
|
-
const
|
|
549
|
-
|
|
550
|
-
if (ev.fields[fk] !== undefined) {
|
|
551
|
-
entries.push([fk, ev.fields[fk]]);
|
|
552
|
-
}
|
|
765
|
+
for (const [fk, fv] of Object.entries(ev.fields)) {
|
|
766
|
+
entries.push([fk, fv]);
|
|
553
767
|
}
|
|
554
768
|
return entries;
|
|
555
769
|
}
|
|
@@ -663,6 +877,49 @@ function dashboard() {
|
|
|
663
877
|
return String(s).replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
|
|
664
878
|
},
|
|
665
879
|
|
|
880
|
+
async fetchArtifacts() {
|
|
881
|
+
if (!this.selectedRun) return;
|
|
882
|
+
try {
|
|
883
|
+
const res = await fetch('/api/runs/' + this.selectedRun + '/artifacts');
|
|
884
|
+
if (res.ok) this.artifactsData = await res.json();
|
|
885
|
+
} catch (e) { /* ignore */ }
|
|
886
|
+
},
|
|
887
|
+
|
|
888
|
+
async viewArtifactDoc(path) {
|
|
889
|
+
if (!this.selectedRun) return;
|
|
890
|
+
try {
|
|
891
|
+
const res = await fetch('/api/runs/' + this.selectedRun + '/artifact?path=' + encodeURIComponent(path));
|
|
892
|
+
if (res.ok) {
|
|
893
|
+
this.artifactDocContent = await res.text();
|
|
894
|
+
this.artifactDocPath = path;
|
|
895
|
+
}
|
|
896
|
+
} catch (e) { /* ignore */ }
|
|
897
|
+
},
|
|
898
|
+
|
|
899
|
+
artifactsCategoryBars() {
|
|
900
|
+
if (!this.artifactsData) return [];
|
|
901
|
+
const ev = this.artifactsData.events;
|
|
902
|
+
const max = Math.max(ev.loop, ev.iteration, ev.backend, ev.review, ev.coordination, ev.operator, ev.routing, ev.errors, 1);
|
|
903
|
+
return [
|
|
904
|
+
{ key: 'loop', label: 'loop', count: ev.loop, pct: (ev.loop / max) * 100, color: 'var(--cat-loop)' },
|
|
905
|
+
{ key: 'iteration', label: 'iteration', count: ev.iteration, pct: (ev.iteration / max) * 100, color: 'var(--cat-iteration)' },
|
|
906
|
+
{ key: 'backend', label: 'backend', count: ev.backend, pct: (ev.backend / max) * 100, color: 'var(--cat-backend)' },
|
|
907
|
+
{ key: 'review', label: 'review', count: ev.review, pct: (ev.review / max) * 100, color: 'var(--cat-review)' },
|
|
908
|
+
{ key: 'coordination', label: 'coord', count: ev.coordination, pct: (ev.coordination / max) * 100, color: 'var(--cat-coordination)' },
|
|
909
|
+
{ key: 'operator', label: 'operator', count: ev.operator, pct: (ev.operator / max) * 100, color: 'var(--cat-operator)' },
|
|
910
|
+
{ key: 'routing', label: 'routing', count: ev.routing, pct: (ev.routing / max) * 100, color: 'var(--cat-routing, #6366f1)' },
|
|
911
|
+
{ key: 'errors', label: 'errors', count: ev.errors, pct: (ev.errors / max) * 100, color: 'var(--cat-error)' },
|
|
912
|
+
];
|
|
913
|
+
},
|
|
914
|
+
|
|
915
|
+
formatBytes(bytes) {
|
|
916
|
+
if (!bytes || bytes === 0) return '0 B';
|
|
917
|
+
if (bytes < 1024) return bytes + ' B';
|
|
918
|
+
const kb = bytes / 1024;
|
|
919
|
+
if (kb < 1024) return kb.toFixed(1) + ' KB';
|
|
920
|
+
return (kb / 1024).toFixed(1) + ' MB';
|
|
921
|
+
},
|
|
922
|
+
|
|
666
923
|
visibleRunEvents() {
|
|
667
924
|
return this.selectedRunEvents.filter(ev => this.showVerbose || !this.isBackendEvent(ev));
|
|
668
925
|
},
|
|
@@ -688,6 +945,65 @@ function dashboard() {
|
|
|
688
945
|
return classes.join(' ');
|
|
689
946
|
},
|
|
690
947
|
|
|
948
|
+
topicCategoryKey(ev) {
|
|
949
|
+
const t = String(ev?.topic || '');
|
|
950
|
+
if (['event.invalid','wave.timeout','wave.failed','loop.stop'].includes(t)) return 'error';
|
|
951
|
+
if (t === 'task.complete' || t === 'loop.complete') return 'completion';
|
|
952
|
+
if (t.startsWith('loop.')) return 'loop';
|
|
953
|
+
if (t.startsWith('iteration.')) return 'iteration';
|
|
954
|
+
if (t.startsWith('backend.')) return 'backend';
|
|
955
|
+
if (t.startsWith('review.')) return 'review';
|
|
956
|
+
if (t.startsWith('operator.')) return 'operator';
|
|
957
|
+
return 'coordination';
|
|
958
|
+
},
|
|
959
|
+
|
|
960
|
+
journalCategoryChips() {
|
|
961
|
+
const counts = {};
|
|
962
|
+
for (const k of Object.keys(this.journalCategoryFilter)) counts[k] = 0;
|
|
963
|
+
for (const ev of this.selectedRunEvents) {
|
|
964
|
+
const cat = this.topicCategoryKey(ev);
|
|
965
|
+
if (cat in counts) counts[cat]++;
|
|
966
|
+
}
|
|
967
|
+
const labels = { loop: 'Loop', iteration: 'Iteration', backend: 'Backend', review: 'Review', coordination: 'Coordination', error: 'Error', operator: 'Operator', completion: 'Completion' };
|
|
968
|
+
return Object.keys(this.journalCategoryFilter).map(key => ({
|
|
969
|
+
key,
|
|
970
|
+
label: labels[key] || key,
|
|
971
|
+
color: this.categoryColors[key] || '#666',
|
|
972
|
+
count: counts[key] || 0,
|
|
973
|
+
enabled: this.journalCategoryFilter[key],
|
|
974
|
+
}));
|
|
975
|
+
},
|
|
976
|
+
|
|
977
|
+
filteredJournalEvents() {
|
|
978
|
+
const search = (this.journalSearch || '').toLowerCase();
|
|
979
|
+
return this.selectedRunEvents.filter(ev => {
|
|
980
|
+
const cat = this.topicCategoryKey(ev);
|
|
981
|
+
if (!this.journalCategoryFilter[cat]) return false;
|
|
982
|
+
if (search) {
|
|
983
|
+
const text = JSON.stringify(ev).toLowerCase();
|
|
984
|
+
if (!text.includes(search)) return false;
|
|
985
|
+
}
|
|
986
|
+
return true;
|
|
987
|
+
});
|
|
988
|
+
},
|
|
989
|
+
|
|
990
|
+
journalGroups() {
|
|
991
|
+
const events = this.filteredJournalEvents();
|
|
992
|
+
const groups = {};
|
|
993
|
+
const order = [];
|
|
994
|
+
for (const ev of events) {
|
|
995
|
+
const iter = ev.iteration;
|
|
996
|
+
const key = iter ? 'iter-' + iter : 'system';
|
|
997
|
+
if (!groups[key]) {
|
|
998
|
+
const label = iter ? '\\u2500\\u2500 iter ' + iter + ' \\u2500\\u2500' : '\\u2500\\u2500 system \\u2500\\u2500';
|
|
999
|
+
groups[key] = { key, label, events: [] };
|
|
1000
|
+
order.push(key);
|
|
1001
|
+
}
|
|
1002
|
+
groups[key].events.push(ev);
|
|
1003
|
+
}
|
|
1004
|
+
return order.map(k => groups[k]);
|
|
1005
|
+
},
|
|
1006
|
+
|
|
691
1007
|
eventSummary(ev) {
|
|
692
1008
|
const parts = [];
|
|
693
1009
|
if (ev.iteration) parts.push('[iter ' + ev.iteration + ']');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shell.js","sourceRoot":"","sources":["../../../src/dashboard/views/shell.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,SAAS;
|
|
1
|
+
{"version":3,"file":"shell.js","sourceRoot":"","sources":["../../../src/dashboard/views/shell.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,SAAS,CAAC,WAAoB;IAC5C,MAAM,WAAW,GAAG,WAAW,IAAI,UAAU,CAAC;IAC9C,OAAO;;;;;oBAKW,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;oEAgJqC,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QA44BvE,CAAC;AACT,CAAC"}
|
package/dist/events/types.d.ts
CHANGED
|
@@ -2,7 +2,8 @@ export type LoopTopic = "loop.start" | "loop.complete" | "loop.stop";
|
|
|
2
2
|
export type IterationTopic = "iteration.start" | "iteration.finish";
|
|
3
3
|
export type BackendTopic = "backend.start" | "backend.finish";
|
|
4
4
|
export type ReviewTopic = "review.start" | "review.finish";
|
|
5
|
-
export type
|
|
5
|
+
export type ArtifactTopic = "artifact.created";
|
|
6
|
+
export type CoordinationTopic = "issue.discovered" | "issue.resolved" | "slice.started" | "slice.verified" | "slice.committed" | "context.archived" | "chain.spawn" | ArtifactTopic;
|
|
6
7
|
export type ChainTopic = "chain.start" | "chain.complete";
|
|
7
8
|
export type OperatorTopic = "operator.guidance" | "operator.guidance.consumed";
|
|
8
9
|
export type WaveTopic = string;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Run artifacts collection and formatting.
|
|
3
|
+
* Aggregates event counts, memory stats, guidance stats, commits,
|
|
4
|
+
* and document artifacts from journal lines.
|
|
5
|
+
*/
|
|
6
|
+
export interface DocumentArtifact {
|
|
7
|
+
path: string;
|
|
8
|
+
kind: string;
|
|
9
|
+
title: string;
|
|
10
|
+
missing: boolean;
|
|
11
|
+
}
|
|
12
|
+
export interface RunArtifacts {
|
|
13
|
+
runId: string;
|
|
14
|
+
preset: string;
|
|
15
|
+
status: string;
|
|
16
|
+
durationMs: number;
|
|
17
|
+
iterations: number;
|
|
18
|
+
events: {
|
|
19
|
+
total: number;
|
|
20
|
+
loop: number;
|
|
21
|
+
iteration: number;
|
|
22
|
+
backend: number;
|
|
23
|
+
review: number;
|
|
24
|
+
coordination: number;
|
|
25
|
+
operator: number;
|
|
26
|
+
routing: number;
|
|
27
|
+
errors: number;
|
|
28
|
+
};
|
|
29
|
+
artifacts: {
|
|
30
|
+
scratchpadEntries: number;
|
|
31
|
+
memoryLearnings: number;
|
|
32
|
+
memoryMeta: number;
|
|
33
|
+
memoryPreferences: number;
|
|
34
|
+
guidanceSent: number;
|
|
35
|
+
guidanceConsumed: number;
|
|
36
|
+
backpressure: number;
|
|
37
|
+
};
|
|
38
|
+
output: {
|
|
39
|
+
commits: number;
|
|
40
|
+
filesChanged: number;
|
|
41
|
+
journalSizeBytes: number;
|
|
42
|
+
};
|
|
43
|
+
documents: DocumentArtifact[];
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Collect aggregated artifacts from journal lines and filesystem.
|
|
47
|
+
*/
|
|
48
|
+
export declare function collectArtifacts(lines: string[], projectDir: string, workDir?: string): RunArtifacts;
|
|
49
|
+
/** Format RunArtifacts into a human-readable terminal string. */
|
|
50
|
+
export declare function formatArtifacts(a: RunArtifacts): string;
|