crewforth 3.1.0-rc.5 → 3.1.0-rc.7
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/CHANGELOG.md +76 -12
- package/README.md +3 -2
- package/kit/AGENT_TEMPLATE.md +41 -21
- package/kit/CLAUDE.md +9 -7
- package/kit/agents/crew-backend-expert.md +4 -1
- package/kit/agents/crew-commit-agent.md +8 -3
- package/kit/agents/crew-database-expert.md +4 -1
- package/kit/agents/crew-devops-expert.md +4 -1
- package/kit/agents/crew-frontend-expert.md +4 -1
- package/kit/agents/crew-performance-expert.md +4 -1
- package/kit/agents/crew-planner.md +10 -1
- package/kit/agents/crew-privacy-agent.md +4 -1
- package/kit/agents/crew-review-agent.md +4 -1
- package/kit/agents/crew-security-expert.md +4 -1
- package/kit/agents/crew-session-manager.md +4 -1
- package/kit/agents/crew-test-expert.md +4 -1
- package/kit/eval/smoke-test.sh +860 -27
- package/kit/hooks/agent-outcome.sh +437 -0
- package/kit/hooks/context-usage.sh +1 -1
- package/kit/hooks/guard-agent-model.sh +494 -60
- package/kit/hooks/guard-bash.sh +69 -8
- package/kit/hooks/guard-schedule.sh +8 -2
- package/kit/hooks/guard-write.sh +31 -0
- package/kit/hooks/prompt-approval.sh +94 -7
- package/kit/settings.json +43 -0
- package/kit/skills/crew-approve/SKILL.md +4 -1
- package/kit/skills/crew-loosen/SKILL.md +28 -0
- package/kit/studio/server/hooks/studio-gate.sh +90 -4
- package/kit/studio/server/hooks/studio-host.mjs +92 -0
- package/kit/studio/server/index.js +85 -6
- package/kit/studio/server/lib/agent-origin.js +44 -0
- package/kit/studio/server/lib/graph.js +45 -7
- package/kit/studio/server/lib/model-outcomes.js +287 -0
- package/kit/studio/server/lib/palette.js +5 -18
- package/kit/studio/server/lib/permissions.js +260 -17
- package/kit/studio/server/lib/session.js +41 -1
- package/kit/studio/server/lib/usage.js +8 -1
- package/kit/studio/web/app.js +203 -32
- package/kit/studio/web/approvals.js +53 -2
- package/kit/studio/web/ask.js +137 -0
- package/kit/studio/web/canvas.js +91 -42
- package/kit/studio/web/chat.js +11 -1
- package/kit/studio/web/convo.js +9 -0
- package/kit/studio/web/dock.js +30 -9
- package/kit/studio/web/graph-plan.js +29 -9
- package/kit/studio/web/icons/builtin.svg +1 -1
- package/kit/studio/web/index.html +11 -4
- package/kit/studio/web/keys.js +29 -0
- package/kit/studio/web/list-plan.js +8 -3
- package/kit/studio/web/list.js +27 -5
- package/kit/studio/web/models-plan.js +167 -0
- package/kit/studio/web/models.js +127 -0
- package/kit/studio/web/names.js +30 -0
- package/kit/studio/web/style.css +85 -9
- package/kit/studio/web/timeline-plan.js +8 -0
- package/kit/studio/web/timeline.js +26 -7
- package/package.json +1 -1
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// Which rows there are, where a bar starts and ends and what it says is decided in timeline-plan.js. This file
|
|
4
4
|
// draws that, and hands back what the viewer did: a row chosen, a group folded, the view moved.
|
|
5
5
|
import {
|
|
6
|
-
rows, groupsOf, extent, windowOf, place, ticks, clock, stepRange, waitNote, factsOf, xOf, RANGES, DEFAULT_RANGE,
|
|
6
|
+
rows, groupsOf, foldedSet, extent, windowOf, place, ticks, clock, stepRange, waitNote, factsOf, xOf, RANGES, DEFAULT_RANGE,
|
|
7
7
|
} from './timeline-plan.js';
|
|
8
8
|
import { Press } from './press.js';
|
|
9
9
|
import { shownType, hoverOf, modelOf, modelFamily } from './names.js';
|
|
@@ -39,7 +39,8 @@ export class Timeline {
|
|
|
39
39
|
this.range = DEFAULT_RANGE;
|
|
40
40
|
this.follow = true;
|
|
41
41
|
this.end = null; // where the view ends when it is not following
|
|
42
|
-
this.
|
|
42
|
+
this.fold = new Map(); // group id -> folded, the viewer's own choices
|
|
43
|
+
this.all = null; // true after Expand all, false after Fold all: what an untouched group is
|
|
43
44
|
this.expanded = new Set();
|
|
44
45
|
this.waiting = new Set();
|
|
45
46
|
this.filter = null; // Set of statuses, or null
|
|
@@ -103,7 +104,8 @@ export class Timeline {
|
|
|
103
104
|
if (id === this.session) return;
|
|
104
105
|
this.session = id;
|
|
105
106
|
this.nodes = [];
|
|
106
|
-
this.
|
|
107
|
+
this.fold = new Map(); // group id -> folded, the viewer's own choices
|
|
108
|
+
this.all = null; // true after Expand all, false after Fold all: what an untouched group is
|
|
107
109
|
this.expanded = new Set();
|
|
108
110
|
this.selected = null;
|
|
109
111
|
this.follow = true;
|
|
@@ -113,7 +115,21 @@ export class Timeline {
|
|
|
113
115
|
}
|
|
114
116
|
|
|
115
117
|
setNodes(nodes) { this.nodes = nodes ?? []; this.render(); }
|
|
116
|
-
setGroup(g) { if (g === this.group) return; this.group = g; this.
|
|
118
|
+
setGroup(g) { if (g === this.group) return; this.group = g; this.fold = new Map(); this.all = null; this.expanded = new Set(); this.render(); }
|
|
119
|
+
|
|
120
|
+
/** Open every group and show every row of the long ones; a group that arrives later arrives open. */
|
|
121
|
+
expandAll() { this.all = true; this.fold = new Map(); this.render(); this.#changed(); }
|
|
122
|
+
/** Fold every group; one that arrives later arrives folded. */
|
|
123
|
+
foldAll() { this.all = false; this.fold = new Map(); this.expanded = new Set(); this.render(); this.#changed(); }
|
|
124
|
+
/** Whether there is anything left for each of the two to do. */
|
|
125
|
+
foldState() {
|
|
126
|
+
const heads = (this.lastRows ?? []).filter((r) => r.kind === 'group');
|
|
127
|
+
return {
|
|
128
|
+
groups: heads.length,
|
|
129
|
+
canExpand: heads.some((r) => r.folded) || (this.lastRows ?? []).some((r) => r.kind === 'more'),
|
|
130
|
+
canFold: heads.some((r) => !r.folded),
|
|
131
|
+
};
|
|
132
|
+
}
|
|
117
133
|
setWaiting(ids) { this.waiting = new Set(ids ?? []); this.render(); }
|
|
118
134
|
setFilter(statuses, { keepWaiting = false } = {}) { this.filter = statuses ? new Set(statuses) : null; this.keepWaiting = keepWaiting; this.render(); }
|
|
119
135
|
setModelFilter(family) { this.modelFilter = family ?? null; this.render(); }
|
|
@@ -151,7 +167,7 @@ export class Timeline {
|
|
|
151
167
|
if (id) {
|
|
152
168
|
for (const g of groupsOf(this.nodes, this.group)) {
|
|
153
169
|
if (!g.members.some((m) => m.id === id)) continue;
|
|
154
|
-
this.
|
|
170
|
+
this.fold.set(g.id, false);
|
|
155
171
|
this.expanded.add(g.id);
|
|
156
172
|
}
|
|
157
173
|
}
|
|
@@ -212,10 +228,12 @@ export class Timeline {
|
|
|
212
228
|
// The rows are drawn again from the data each time; a keyboard reader's place among them is kept.
|
|
213
229
|
const focused = this.rowsEl.contains?.(document.activeElement) ? document.activeElement.dataset?.key ?? null : null;
|
|
214
230
|
const top = this.body.scrollTop;
|
|
231
|
+
const ids = groupsOf(this.nodes, this.group).map((g) => g.id);
|
|
215
232
|
const list = rows(this.nodes, {
|
|
216
|
-
group: this.group, folded: this.
|
|
233
|
+
group: this.group, folded: foldedSet(ids, this.fold, this.all), expanded: this.all === true ? new Set(ids) : this.expanded, waiting: this.waiting,
|
|
217
234
|
approvals: this.owned?.approvals ?? null, now,
|
|
218
235
|
});
|
|
236
|
+
this.lastRows = list;
|
|
219
237
|
this.rowsEl.replaceChildren(...list.map((r) => this.#row(r, win, width)));
|
|
220
238
|
this.body.scrollTop = top;
|
|
221
239
|
if (focused) [...this.rowsEl.querySelectorAll('[data-key]')].find((el) => el.dataset.key === focused)?.focus();
|
|
@@ -305,8 +323,9 @@ export class Timeline {
|
|
|
305
323
|
chev.innerHTML = '<svg class="ic" viewBox="0 0 16 16" aria-hidden="true"><path d="M6 4l4 4-4 4"/></svg>';
|
|
306
324
|
lab.append(chev, mk('span', 'tl-name', r.label), mk('span', 'row-fill'), mk('span', 'sub', r.sub));
|
|
307
325
|
lab.addEventListener('click', () => {
|
|
308
|
-
|
|
326
|
+
this.fold.set(r.id, !r.folded);
|
|
309
327
|
this.render();
|
|
328
|
+
this.#changed();
|
|
310
329
|
});
|
|
311
330
|
this.#bars(track, r.lanes, win, width);
|
|
312
331
|
} else if (r.kind === 'merged') {
|
package/package.json
CHANGED