@mobrienv/autoloop 0.2.1 → 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/agent-map.js.map +1 -1
- 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 +38 -4
- package/dist/backend/kiro-bridge.js.map +1 -1
- package/dist/backend/kiro-worker.js +20 -7
- package/dist/backend/kiro-worker.js.map +1 -1
- package/dist/backend/run-kiro.js +5 -1
- package/dist/backend/run-kiro.js.map +1 -1
- package/dist/chains/load.js +1 -1
- package/dist/chains/load.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/guide.d.ts +1 -0
- package/dist/commands/guide.js +33 -0
- package/dist/commands/guide.js.map +1 -0
- package/dist/commands/inspect.js +45 -5
- package/dist/commands/inspect.js.map +1 -1
- package/dist/commands/run.js +6 -1
- package/dist/commands/run.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 +84 -1
- 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 +366 -18
- package/dist/dashboard/views/shell.js.map +1 -1
- package/dist/events/types.d.ts +4 -2
- 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 +10 -10
- package/dist/harness/config-helpers.js.map +1 -1
- package/dist/harness/emit.js +2 -0
- package/dist/harness/emit.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/harness/journal.d.ts +1 -0
- package/dist/harness/journal.js +3 -0
- package/dist/harness/journal.js.map +1 -1
- package/dist/harness/metareview.js +1 -1
- package/dist/harness/metareview.js.map +1 -1
- package/dist/harness/prompt.d.ts +2 -0
- package/dist/harness/prompt.js +45 -6
- package/dist/harness/prompt.js.map +1 -1
- package/dist/harness/types.d.ts +2 -2
- 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/main.js +5 -0
- package/dist/main.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 +21 -4
- package/plugins/autoloop/.claude-plugin/plugin.json +9 -0
- package/plugins/autoloop/skills/autoloop/SKILL.md +225 -0
- 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,6 +356,133 @@ 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>
|
|
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>
|
|
485
|
+
</div>
|
|
305
486
|
</div>
|
|
306
487
|
|
|
307
488
|
<script defer src="/static/alpine.min.js"></script>
|
|
@@ -319,15 +500,51 @@ function dashboard() {
|
|
|
319
500
|
lastUpdated: null,
|
|
320
501
|
sectionOpen: { active: false, watching: false, stuck: false, failed: false, completed: false },
|
|
321
502
|
sectionUserToggled: {},
|
|
503
|
+
sectionShowAll: {},
|
|
322
504
|
showVerbose: false,
|
|
505
|
+
guideMessage: "",
|
|
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
|
+
},
|
|
323
532
|
|
|
324
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);
|
|
325
542
|
return [
|
|
326
|
-
{ key: "active", label: "Active", items: this.runs.active },
|
|
327
|
-
{ key: "watching", label: "Watching", items: this.runs.watching },
|
|
328
|
-
{ key: "stuck", label: "Stuck", items: this.runs.stuck },
|
|
329
|
-
{ key: "failed", label: "Failed", items:
|
|
330
|
-
{ 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 },
|
|
331
548
|
];
|
|
332
549
|
},
|
|
333
550
|
|
|
@@ -340,7 +557,12 @@ function dashboard() {
|
|
|
340
557
|
async fetchRuns() {
|
|
341
558
|
try {
|
|
342
559
|
const res = await fetch("/api/runs");
|
|
343
|
-
|
|
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;
|
|
344
566
|
this.lastUpdated = new Date().toLocaleTimeString();
|
|
345
567
|
const defaultOpen = ['active', 'watching', 'stuck'];
|
|
346
568
|
for (const cat of this.categories) {
|
|
@@ -365,6 +587,9 @@ function dashboard() {
|
|
|
365
587
|
|
|
366
588
|
async selectRun(runId) {
|
|
367
589
|
this.selectedRun = runId;
|
|
590
|
+
this.artifactsData = null;
|
|
591
|
+
this.artifactDocContent = null;
|
|
592
|
+
this.artifactDocPath = '';
|
|
368
593
|
try {
|
|
369
594
|
const detailRes = await fetch("/api/runs/" + runId);
|
|
370
595
|
if (detailRes.ok) this.selectedRunDetail = await detailRes.json();
|
|
@@ -380,6 +605,30 @@ function dashboard() {
|
|
|
380
605
|
} catch (e) { /* ignore */ }
|
|
381
606
|
},
|
|
382
607
|
|
|
608
|
+
async sendGuide() {
|
|
609
|
+
if (!this.guideMessage.trim() || !this.selectedRun) return;
|
|
610
|
+
try {
|
|
611
|
+
const res = await fetch("/api/runs/" + this.selectedRun + "/guide", {
|
|
612
|
+
method: "POST",
|
|
613
|
+
headers: { "Content-Type": "application/json" },
|
|
614
|
+
body: JSON.stringify({ message: this.guideMessage }),
|
|
615
|
+
});
|
|
616
|
+
if (res.ok) {
|
|
617
|
+
this.guideMessage = "";
|
|
618
|
+
this.guideFlash = "Sent";
|
|
619
|
+
setTimeout(() => { this.guideFlash = ""; }, 2000);
|
|
620
|
+
await this.fetchEvents(this.selectedRun);
|
|
621
|
+
} else {
|
|
622
|
+
const data = await res.json().catch(() => ({}));
|
|
623
|
+
this.guideFlash = data.error || "Failed";
|
|
624
|
+
setTimeout(() => { this.guideFlash = ""; }, 3000);
|
|
625
|
+
}
|
|
626
|
+
} catch (e) {
|
|
627
|
+
this.guideFlash = "Error";
|
|
628
|
+
setTimeout(() => { this.guideFlash = ""; }, 3000);
|
|
629
|
+
}
|
|
630
|
+
},
|
|
631
|
+
|
|
383
632
|
async startLoop() {
|
|
384
633
|
if (!this.newPrompt.trim()) return;
|
|
385
634
|
await fetch("/api/runs", {
|
|
@@ -507,17 +756,14 @@ function dashboard() {
|
|
|
507
756
|
},
|
|
508
757
|
|
|
509
758
|
eventDisplayEntries(ev) {
|
|
510
|
-
if (ev.
|
|
759
|
+
if (ev.fields && typeof ev.fields === 'object') {
|
|
511
760
|
const entries = [];
|
|
512
761
|
for (const [k, v] of Object.entries(ev)) {
|
|
513
762
|
if (k === 'fields') continue;
|
|
514
763
|
entries.push([k, v]);
|
|
515
764
|
}
|
|
516
|
-
const
|
|
517
|
-
|
|
518
|
-
if (ev.fields[fk] !== undefined) {
|
|
519
|
-
entries.push([fk, ev.fields[fk]]);
|
|
520
|
-
}
|
|
765
|
+
for (const [fk, fv] of Object.entries(ev.fields)) {
|
|
766
|
+
entries.push([fk, fv]);
|
|
521
767
|
}
|
|
522
768
|
return entries;
|
|
523
769
|
}
|
|
@@ -631,6 +877,49 @@ function dashboard() {
|
|
|
631
877
|
return String(s).replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
|
|
632
878
|
},
|
|
633
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
|
+
|
|
634
923
|
visibleRunEvents() {
|
|
635
924
|
return this.selectedRunEvents.filter(ev => this.showVerbose || !this.isBackendEvent(ev));
|
|
636
925
|
},
|
|
@@ -656,6 +945,65 @@ function dashboard() {
|
|
|
656
945
|
return classes.join(' ');
|
|
657
946
|
},
|
|
658
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
|
+
|
|
659
1007
|
eventSummary(ev) {
|
|
660
1008
|
const parts = [];
|
|
661
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,11 +2,13 @@ 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";
|
|
8
|
+
export type OperatorTopic = "operator.guidance" | "operator.guidance.consumed";
|
|
7
9
|
export type WaveTopic = string;
|
|
8
10
|
export type CoreSystemTopic = LoopTopic | IterationTopic | BackendTopic | ReviewTopic | "event.invalid";
|
|
9
|
-
export type KnownTopic = CoreSystemTopic | CoordinationTopic | ChainTopic | WaveTopic | string;
|
|
11
|
+
export type KnownTopic = CoreSystemTopic | CoordinationTopic | ChainTopic | OperatorTopic | WaveTopic | string;
|
|
10
12
|
export interface EventBase {
|
|
11
13
|
run: string;
|
|
12
14
|
topic: KnownTopic;
|
|
@@ -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;
|