crewforth 3.1.1 → 3.2.0-rc.10
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 +323 -0
- package/README.md +6 -3
- package/VERSION +1 -1
- package/adopt.sh +66 -6
- package/bin/cli.js +3 -2
- package/kit/AGENT_TEMPLATE.md +2 -1
- package/kit/CLAUDE.md +15 -14
- package/kit/agents/crew-commit-agent.md +11 -4
- package/kit/agents/crew-docs-agent.md +71 -0
- package/kit/agents/crew-planner.md +2 -0
- package/kit/agents/crew-refuter.md +77 -0
- package/kit/agents/crew-review-agent.md +2 -0
- package/kit/agents/crew-security-expert.md +3 -1
- package/kit/agents/crew-session-manager.md +11 -9
- package/kit/eval/doctor.sh +128 -6
- package/kit/eval/gate-report.sh +2 -0
- package/kit/eval/golden-routing.txt +9 -0
- package/kit/eval/lib/crew-map/crew-map.sh +26 -0
- package/kit/eval/lib/crew-map/detect.mjs +238 -0
- package/kit/eval/lib/crew-map/narrative.mjs +132 -0
- package/kit/eval/lib/crew-map/parse.mjs +305 -0
- package/kit/eval/lib/crew-map/project.mjs +164 -0
- package/kit/eval/lib/crew-map/rules/names.json +38 -0
- package/kit/eval/lib/crew-map/rules/packages.json +142 -0
- package/kit/eval/lib/crew-map/rules/python-stdlib.json +197 -0
- package/kit/eval/lib/crew-map/rules/tech.json +35 -0
- package/kit/eval/lib/crew-map/scan.mjs +266 -0
- package/kit/eval/lib/crew-map/stacks.mjs +547 -0
- package/kit/eval/lib/crew-map/surface.mjs +535 -0
- package/kit/eval/lib/findings/findings.mjs +410 -0
- package/kit/eval/lib/findings/findings.schema.json +122 -0
- package/kit/eval/lib/findings/findings.sh +29 -0
- package/kit/eval/lib/gate-log.sh +52 -0
- package/kit/eval/lib/json-string.awk +27 -0
- package/kit/eval/lib/preset.sh +109 -0
- package/kit/eval/lib/presets/default.json +7 -0
- package/kit/eval/lib/presets/solo.json +7 -0
- package/kit/eval/lib/presets/strict.json +11 -0
- package/kit/eval/lib/preview.sh +150 -0
- package/kit/eval/lib/review-bench/bench.mjs +273 -0
- package/kit/eval/lib/review-prepass/prepass.mjs +203 -0
- package/kit/eval/lib/review-prepass/prepass.sh +23 -0
- package/kit/eval/lib/settings-default.sh +36 -0
- package/kit/eval/lib/settings-json.awk +19 -4
- package/kit/eval/lib/star.sh +23 -7
- package/kit/eval/lib/statusline.settings.json +6 -0
- package/kit/eval/lib/statusline.sh +100 -0
- package/kit/eval/lib/verify-cmd.sh +17 -0
- package/kit/eval/lib/version.sh +41 -0
- package/kit/eval/review-bench.sh +26 -0
- package/kit/eval/smoke-test.sh +878 -53
- package/kit/hooks/agent-outcome.sh +44 -12
- package/kit/hooks/board-sync.sh +2 -23
- package/kit/hooks/guard-agent-model.sh +177 -24
- package/kit/hooks/guard-bash.sh +295 -204
- package/kit/hooks/guard-commit-scan.sh +10 -2
- package/kit/hooks/guard-question.sh +73 -0
- package/kit/hooks/guard-write.sh +24 -7
- package/kit/hooks/precompact-snapshot.sh +75 -0
- package/kit/hooks/prompt-approval.sh +389 -103
- package/kit/hooks/refuter-ledger.sh +80 -0
- package/kit/hooks/session-rehydrate.sh +25 -2
- package/kit/hooks/session-update-check.sh +9 -8
- package/kit/hooks/trace-blocklist.txt +9 -0
- package/kit/owned-blobs.tsv +4 -4
- package/kit/settings.json +51 -0
- package/kit/skills/crew-approve/SKILL.md +7 -0
- package/kit/skills/crew-code-review/SKILL.md +16 -0
- package/kit/skills/crew-doctor/SKILL.md +5 -1
- package/kit/skills/crew-handoff/SKILL.md +3 -2
- package/kit/skills/crew-map/SKILL.md +55 -0
- package/kit/skills/crew-review/SKILL.md +4 -1
- package/kit/skills/crew-ship/SKILL.md +3 -1
- package/kit/skills/crew-update/SKILL.md +1 -1
- package/kit/skills/incident-runbook/SKILL.md +2 -2
- package/kit/skills/security-scan/references/verify.md +6 -3
- package/kit/studio/README.md +25 -2
- package/kit/studio/server/index.js +187 -21
- package/kit/studio/server/lib/code-stamp.js +35 -0
- package/kit/studio/server/lib/crew-map.js +113 -0
- package/kit/studio/server/lib/graph.js +9 -1
- package/kit/studio/server/lib/kit-telemetry.js +30 -5
- package/kit/studio/server/lib/lan.js +87 -0
- package/kit/studio/server/lib/model-outcomes.js +130 -15
- package/kit/studio/server/lib/owned-stream.js +56 -0
- package/kit/studio/server/lib/pricing.js +3 -0
- package/kit/studio/server/lib/projects.js +11 -4
- package/kit/studio/server/lib/redact.js +60 -0
- package/kit/studio/server/lib/remote.js +185 -0
- package/kit/studio/server/lib/session.js +1 -1
- package/kit/studio/server/lib/terminal.js +51 -13
- package/kit/studio/server/lib/transcript.js +32 -0
- package/kit/studio/server/lib/usage.js +74 -14
- package/kit/studio/web/app.js +287 -17
- package/kit/studio/web/canvas.js +58 -122
- package/kit/studio/web/chat.js +114 -24
- package/kit/studio/web/graph-plan.js +13 -6
- package/kit/studio/web/index.html +10 -5
- package/kit/studio/web/liveness.js +14 -0
- package/kit/studio/web/map-plan.js +410 -0
- package/kit/studio/web/map.js +596 -0
- package/kit/studio/web/models-plan.js +61 -7
- package/kit/studio/web/models.js +19 -3
- package/kit/studio/web/qr.js +200 -0
- package/kit/studio/web/style.css +165 -0
- package/kit/studio/web/tokens.css +6 -0
- package/kit/studio/web/usage.js +12 -0
- package/kit/studio/web/viewport.js +160 -0
- package/package.json +6 -5
- package/start.sh +24 -1
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
// A pane that pans and zooms one layer, and cards that can be dragged on it.
|
|
2
|
+
//
|
|
3
|
+
// The graph (canvas.js) and the project map (map.js) both draw cards on a layer the viewer moves around. This is
|
|
4
|
+
// that part, once: a drag on the empty pane pans, the wheel zooms about the pointer (or pans, when it is mostly
|
|
5
|
+
// sideways), Fit puts the whole picture in the pane, and a card dragged more than a few pixels is placed by hand.
|
|
6
|
+
// Where things go and what a card says stay with the view that owns them.
|
|
7
|
+
import { ZOOM, fitZoom } from './graph-plan.js';
|
|
8
|
+
|
|
9
|
+
const clamp = (v, lo, hi) => Math.min(hi, Math.max(lo, v));
|
|
10
|
+
|
|
11
|
+
export class Viewport {
|
|
12
|
+
/**
|
|
13
|
+
* @param pane the element the pointer works on; its size is the pane's
|
|
14
|
+
* @param layer the element moved and scaled: one transform, so a zoom restyles nothing
|
|
15
|
+
* @param skip (target) => true when a press on it is not a pan (a card, a control on the pane)
|
|
16
|
+
* @param onApply called after every change of the view
|
|
17
|
+
*/
|
|
18
|
+
constructor(pane, layer, { skip = () => false, onApply = () => {} } = {}) {
|
|
19
|
+
this.pane = pane;
|
|
20
|
+
this.layer = layer;
|
|
21
|
+
this.skip = skip;
|
|
22
|
+
this.onApply = onApply;
|
|
23
|
+
this.view = { x: 0, y: 0, k: 1 };
|
|
24
|
+
this.touched = false; // the viewer moved the view themselves
|
|
25
|
+
this.#wire();
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
#wire() {
|
|
29
|
+
let panning = null;
|
|
30
|
+
this.pane.addEventListener('pointerdown', (e) => {
|
|
31
|
+
if (e.button !== 0) return; // right/middle must not pan
|
|
32
|
+
if (this.skip(e.target)) return;
|
|
33
|
+
panning = { px: e.clientX, py: e.clientY, x: this.view.x, y: this.view.y };
|
|
34
|
+
this.pane.setPointerCapture(e.pointerId);
|
|
35
|
+
this.pane.classList.add('cv-panning');
|
|
36
|
+
});
|
|
37
|
+
this.pane.addEventListener('pointermove', (e) => {
|
|
38
|
+
if (!panning) return;
|
|
39
|
+
this.view.x = panning.x + (e.clientX - panning.px);
|
|
40
|
+
this.view.y = panning.y + (e.clientY - panning.py);
|
|
41
|
+
this.touched = true;
|
|
42
|
+
this.apply();
|
|
43
|
+
});
|
|
44
|
+
const endPan = () => { panning = null; this.pane.classList.remove('cv-panning'); };
|
|
45
|
+
this.pane.addEventListener('pointerup', endPan);
|
|
46
|
+
this.pane.addEventListener('pointercancel', endPan);
|
|
47
|
+
|
|
48
|
+
this.pane.addEventListener('wheel', (e) => {
|
|
49
|
+
e.preventDefault();
|
|
50
|
+
const r = this.pane.getBoundingClientRect();
|
|
51
|
+
const mx = e.clientX - r.left;
|
|
52
|
+
const my = e.clientY - r.top;
|
|
53
|
+
// deltaMode 1 is lines and 2 is pages; Firefox reports ~3 where Chrome reports ~100, which made zoom
|
|
54
|
+
// imperceptible and pan crawl.
|
|
55
|
+
const unit = e.deltaMode === 1 ? 16 : e.deltaMode === 2 ? r.height : 1;
|
|
56
|
+
const dY = e.deltaY * unit;
|
|
57
|
+
const dX = e.deltaX * unit;
|
|
58
|
+
if (e.ctrlKey || e.metaKey || Math.abs(dY) > Math.abs(dX)) {
|
|
59
|
+
this.zoomAbout(this.view.k * Math.exp(-dY * 0.0016), mx, my);
|
|
60
|
+
} else {
|
|
61
|
+
this.view.x -= dX;
|
|
62
|
+
this.view.y -= dY;
|
|
63
|
+
}
|
|
64
|
+
this.touched = true;
|
|
65
|
+
this.apply();
|
|
66
|
+
}, { passive: false });
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** Zoom to `k`, keeping the world point under (mx, my) where it is. */
|
|
70
|
+
zoomAbout(k, mx, my) {
|
|
71
|
+
const next = clamp(k, ZOOM.min, ZOOM.max);
|
|
72
|
+
this.view.x = mx - (mx - this.view.x) * (next / this.view.k);
|
|
73
|
+
this.view.y = my - (my - this.view.y) * (next / this.view.k);
|
|
74
|
+
this.view.k = next;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/** Step the zoom from a toolbar: about the middle of the pane. */
|
|
78
|
+
zoomBy(factor) { this.zoomTo(this.view.k * factor); }
|
|
79
|
+
|
|
80
|
+
zoomTo(k) {
|
|
81
|
+
const r = this.pane.getBoundingClientRect();
|
|
82
|
+
this.zoomAbout(k, r.width / 2, r.height / 2);
|
|
83
|
+
this.touched = true;
|
|
84
|
+
this.apply();
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/** Turn `view` into pixels: the single place that does. */
|
|
88
|
+
apply() {
|
|
89
|
+
const { x, y, k } = this.view;
|
|
90
|
+
this.layer.style.transform = `translate(${x}px, ${y}px) scale(${k})`;
|
|
91
|
+
this.onApply();
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/** The whole picture (width × height, in the layer's own pixels) in the pane, never above 100%. */
|
|
95
|
+
/** Fit the picture to the pane; `floor` is a zoom it does not go under (the picture then starts at its top). */
|
|
96
|
+
fit(width, height, floor = 0) {
|
|
97
|
+
const r = this.pane.getBoundingClientRect();
|
|
98
|
+
const k = Math.max(fitZoom(width, height, r.width, r.height), Math.min(floor, ZOOM.fitMax));
|
|
99
|
+
this.view.k = k;
|
|
100
|
+
this.view.x = Math.max(ZOOM.pad, (r.width - width * k) / 2);
|
|
101
|
+
this.view.y = Math.max(ZOOM.pad, (r.height - height * k) / 2);
|
|
102
|
+
this.touched = false;
|
|
103
|
+
this.apply();
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/** Bring a point of the layer to the middle of the pane, at least at `minK`. */
|
|
107
|
+
centerOn(cx, cy, minK = 1) {
|
|
108
|
+
const r = this.pane.getBoundingClientRect();
|
|
109
|
+
this.view.k = clamp(Math.max(this.view.k, minK), ZOOM.min, ZOOM.max);
|
|
110
|
+
this.view.x = r.width / 2 - cx * this.view.k;
|
|
111
|
+
this.view.y = r.height / 2 - cy * this.view.k;
|
|
112
|
+
this.touched = true;
|
|
113
|
+
this.apply();
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* A card that can be placed by hand. A press that moves more than 3 px (at the pane's zoom) is a drag, and the
|
|
119
|
+
* click that ends it is swallowed: without that, every reposition also toggled the selection.
|
|
120
|
+
* @param scale () => the pane's zoom
|
|
121
|
+
* @param at () => the card's position { x, y } when the drag starts
|
|
122
|
+
* @param move (x, y) => the card is now here
|
|
123
|
+
* @param end () => the drag is over (persist the place)
|
|
124
|
+
* @param ignore (target) => true for a part of the card that answers the press itself
|
|
125
|
+
*/
|
|
126
|
+
export function draggable(el, { scale, at, move, end = () => {}, ignore = () => false }) {
|
|
127
|
+
let drag = null;
|
|
128
|
+
el.addEventListener('pointerdown', (e) => {
|
|
129
|
+
if (e.button !== 0) return;
|
|
130
|
+
e.stopPropagation(); // do not pan the pane too
|
|
131
|
+
if (ignore(e.target)) return;
|
|
132
|
+
const p = at() ?? { x: 0, y: 0 };
|
|
133
|
+
drag = { px: e.clientX, py: e.clientY, x: p.x, y: p.y, moved: false };
|
|
134
|
+
el.setPointerCapture(e.pointerId);
|
|
135
|
+
});
|
|
136
|
+
el.addEventListener('pointermove', (e) => {
|
|
137
|
+
if (!drag) return;
|
|
138
|
+
const dx = (e.clientX - drag.px) / scale();
|
|
139
|
+
const dy = (e.clientY - drag.py) / scale();
|
|
140
|
+
if (!drag.moved && Math.abs(dx) <= 3 && Math.abs(dy) <= 3) return;
|
|
141
|
+
drag.moved = true;
|
|
142
|
+
el.classList.add('cv-dragging');
|
|
143
|
+
move(Math.round(drag.x + dx), Math.round(drag.y + dy));
|
|
144
|
+
});
|
|
145
|
+
const stop = () => {
|
|
146
|
+
if (!drag) return;
|
|
147
|
+
if (drag.moved) { end(); el.dataset.suppressClick = '1'; }
|
|
148
|
+
drag = null;
|
|
149
|
+
el.classList.remove('cv-dragging');
|
|
150
|
+
};
|
|
151
|
+
el.addEventListener('pointerup', stop);
|
|
152
|
+
el.addEventListener('pointercancel', stop);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/** Did a drag just end on this element? Answers once, so the click that ends a drag does nothing. */
|
|
156
|
+
export function swallowClick(el) {
|
|
157
|
+
if (el.dataset.suppressClick !== '1') return false;
|
|
158
|
+
el.dataset.suppressClick = '0';
|
|
159
|
+
return true;
|
|
160
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "crewforth",
|
|
3
|
-
"version": "3.
|
|
4
|
-
"description": "Crewforth
|
|
3
|
+
"version": "3.2.0-rc.10",
|
|
4
|
+
"description": "Crewforth — your engineering crew for Claude Code: agents, skills and tool-level gates, in any stack.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"crewforth": "bin/cli.js"
|
|
7
7
|
},
|
|
@@ -15,7 +15,8 @@
|
|
|
15
15
|
"kit/",
|
|
16
16
|
"VERSION",
|
|
17
17
|
"LICENSE",
|
|
18
|
-
"README.md",
|
|
18
|
+
"README.md",
|
|
19
|
+
"CHANGELOG.md"
|
|
19
20
|
],
|
|
20
21
|
"engines": {
|
|
21
22
|
"node": ">=20"
|
|
@@ -42,10 +43,10 @@
|
|
|
42
43
|
"code-review",
|
|
43
44
|
"git-hooks"
|
|
44
45
|
],
|
|
45
|
-
"author": "
|
|
46
|
+
"author": "Barış Yerlikaya",
|
|
46
47
|
"homepage": "https://crewforth.com/",
|
|
47
48
|
"repository": {
|
|
48
49
|
"type": "git",
|
|
49
|
-
"url": "git+https://github.com/
|
|
50
|
+
"url": "git+https://github.com/crewforth/crewforth.git"
|
|
50
51
|
}
|
|
51
52
|
}
|
package/start.sh
CHANGED
|
@@ -96,6 +96,8 @@ _mt() { # $1 = English text (the key); further args fill %s; result in _M
|
|
|
96
96
|
if [ "$CREW_LANG" = tr ]; then
|
|
97
97
|
case "$s" in
|
|
98
98
|
"Crewforth · setup wizard") s='Crewforth · kurulum' ;;
|
|
99
|
+
"Status line: Crewforth's (the gate's last word, a standing approval, crew agents, fill, cost).") s="Durum satırı: Crewforth'unki (kapının son sözü, geçerli onay, crew ajanları, doluluk, maliyet)." ;;
|
|
100
|
+
"Status line: yours is kept; Crewforth's is one command away (see /crew-doctor).") s="Durum satırı: seninki korundu; Crewforth'unki tek komutla açılır (/crew-doctor'a bak)." ;;
|
|
99
101
|
"stack-agnostic") s='her yığınla çalışır' ;;
|
|
100
102
|
"[1/2] Who is this install for?") s='[1/2] Kurulumu kim kullanacak?' ;;
|
|
101
103
|
"Decides whether your teammates get Crewforth's configuration — and what goes into .gitignore.") s="Crewforth ayarlarının ekiple paylaşılıp paylaşılmayacağını ve .gitignore'a nelerin ekleneceğini belirler." ;;
|
|
@@ -189,6 +191,8 @@ Crewforth her zaman eksiksiz kurulur: tüm ajanlar ve skill'ler — backend, web
|
|
|
189
191
|
(CLAUDE.md ## Stack ya da depo). React Native/Expo, hazır isteğe bağlı katmanlardan yalnız biridir.
|
|
190
192
|
--backend | --frontend | --mobile | --fullstack hâlâ kabul edilir ama etkisi yok (eski komutlar bozulmasın diye)
|
|
191
193
|
--private | --shared kurulum yalnızca sizin mi, yoksa ekiple paylaşılıp commit'lenecek mi? (varsayılan: private)
|
|
194
|
+
--preset <ad|dosya> bir kurum preset'i uygula: kritik yollar, model tabanları, izinli verify komutları
|
|
195
|
+
(gelenler: default, strict, solo; ya da kendi .json dosyanız)
|
|
192
196
|
--lang tr|en kurulum dili (verilmezse sihirbaz sorar)
|
|
193
197
|
--yes, -y tüm sorulara evet de (gözetimsiz kurulum)
|
|
194
198
|
--version, -v Crewforth sürümünü yazdırıp çık
|
|
@@ -207,6 +211,8 @@ Every install ships everything: all agents, all skills — backend, web and mobi
|
|
|
207
211
|
(CLAUDE.md ## Stack, or the repo). React Native/Expo is only one of the optional ready-made layers.
|
|
208
212
|
--backend | --frontend | --mobile | --fullstack accepted, no effect (kept so older commands still run)
|
|
209
213
|
--private | --shared is the install yours alone, or committed for the team? (default: private)
|
|
214
|
+
--preset <name|file> apply an organisation preset: critical paths, model floors, allowed verify commands
|
|
215
|
+
(shipped: default, strict, solo; or a .json file of your own)
|
|
210
216
|
--lang tr|en installer language (asked interactively when not given)
|
|
211
217
|
--yes, -y answer every question with yes (unattended install)
|
|
212
218
|
--version, -v print the Crewforth version and exit
|
|
@@ -430,9 +436,13 @@ case "$CREW_LANG" in tr|en) ;; *) CREW_LANG=en ;; esac
|
|
|
430
436
|
# choice made by --lang or the menu above stayed in this shell, and the preflight block printed English.
|
|
431
437
|
export CREW_LANG
|
|
432
438
|
|
|
433
|
-
STACK="generic"; DOTNET_FLAG=0; LEGACY_FLAGS=""; ASSUME_YES=0; VISIBILITY=""
|
|
439
|
+
STACK="generic"; DOTNET_FLAG=0; LEGACY_FLAGS=""; ASSUME_YES=0; VISIBILITY=""; PRESET=""; _preset_take=0
|
|
434
440
|
for a in "$@"; do
|
|
441
|
+
# `--preset NAME`: the next word is its value, whatever it looks like (`--preset strict`, `--preset ./org.json`).
|
|
442
|
+
if [ "$_preset_take" = 1 ]; then _preset_take=0; PRESET="$a"; continue; fi
|
|
435
443
|
case "$a" in
|
|
444
|
+
--preset=*) PRESET="${a#--preset=}" ;;
|
|
445
|
+
--preset) _preset_take=1 ;;
|
|
436
446
|
--lang) ;; # value consumed in the language pass above
|
|
437
447
|
--lang=*) ;;
|
|
438
448
|
tr|en) ;; # the value of a separated --lang
|
|
@@ -446,6 +456,9 @@ for a in "$@"; do
|
|
|
446
456
|
*) printf '%s\n' "$(m 'Unknown parameter: %s' "$a")"; echo; usage; exit 1 ;;
|
|
447
457
|
esac
|
|
448
458
|
done
|
|
459
|
+
[ "$_preset_take" = 1 ] && { printf '%s\n' "$(m 'Unknown parameter: %s' "--preset (no value)")"; echo; usage; exit 1; }
|
|
460
|
+
# A preset is checked before anything is installed: one that is not valid stops here, with nothing written.
|
|
461
|
+
if [ -n "$PRESET" ]; then bash "$SRC/eval/lib/preset.sh" --check "$PRESET" || exit 1; fi
|
|
449
462
|
|
|
450
463
|
# ===================== COLOR / STYLE HELPERS =====================
|
|
451
464
|
# Color is emitted ONLY on an interactive TTY + TERM!=dumb + NO_COLOR empty.
|
|
@@ -638,6 +651,14 @@ count_showcase .claude/skills
|
|
|
638
651
|
# studio's gate hook is invoked as `bash <path>` today, so the bit is not load-bearing
|
|
639
652
|
# yet; set it anyway, because a future direct exec would fail silently.
|
|
640
653
|
chmod +x .claude/hooks/*.sh .claude/hooks/pre-commit .claude/hooks/commit-msg .claude/eval/*.sh .claude/studio/server/hooks/*.sh 2>/dev/null || true
|
|
654
|
+
# The status line, only where none is set: a user's own would lose to the project's setting, so it is never
|
|
655
|
+
# replaced. eval/lib/statusline.sh --install decides and writes; this only says what it did.
|
|
656
|
+
if [ -f .claude/eval/lib/statusline.sh ]; then
|
|
657
|
+
case "$(bash .claude/eval/lib/statusline.sh --install 2>/dev/null)" in
|
|
658
|
+
installed) _mt "Status line: Crewforth's (the gate's last word, a standing approval, crew agents, fill, cost)."; echo " ${_M}" ;;
|
|
659
|
+
kept) _mt "Status line: yours is kept; Crewforth's is one command away (see /crew-doctor)."; echo " ${_M}" ;;
|
|
660
|
+
esac
|
|
661
|
+
fi
|
|
641
662
|
|
|
642
663
|
# §4.2: a vendor line that was armed before this run stays armed (the copy above resets it to a comment); nothing
|
|
643
664
|
# else arms it. Rationale, and the measured failure of "arm it whenever the pattern skill exists", in adopt.sh.
|
|
@@ -679,6 +700,8 @@ cp "$SRC/README.md" .claude/ 2>/dev/null || true
|
|
|
679
700
|
# as if somebody had chosen it. --lang, CREW_LANG and the menu are choices, and are.
|
|
680
701
|
[ "${_LANG_GUESSED:-0}" = 1 ] || echo "lang=${CREW_LANG:-en}"
|
|
681
702
|
} > .claude/kit.conf
|
|
703
|
+
# The organisation's preset, now that .claude/ is in place (checked above): a block at the top of crew-model-rules.
|
|
704
|
+
if [ -n "$PRESET" ]; then bash .claude/eval/lib/preset.sh --apply "$PRESET" || exit 1; fi
|
|
682
705
|
|
|
683
706
|
# Discipline (kit-owned, refreshed on every update) vs project section (yours, written once), joined by @import.
|
|
684
707
|
kit_require_sentinel "$SRC/CLAUDE.md"
|