crewforth 3.4.0 → 3.5.0-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +241 -0
- package/README.md +3 -2
- package/VERSION +1 -1
- package/adopt.sh +40 -5
- package/bin/cli.js +138 -2
- package/kit/AGENT_TEMPLATE.md +15 -0
- package/kit/CLAUDE.md +49 -17
- package/kit/agents/crew-backend-expert.md +4 -3
- package/kit/agents/crew-commit-agent.md +2 -0
- package/kit/agents/crew-database-expert.md +2 -1
- package/kit/agents/crew-devops-expert.md +1 -0
- package/kit/agents/crew-docs-agent.md +3 -1
- package/kit/agents/crew-frontend-expert.md +2 -0
- package/kit/agents/crew-performance-expert.md +7 -2
- package/kit/agents/crew-planner.md +15 -3
- package/kit/agents/crew-privacy-agent.md +2 -0
- package/kit/agents/crew-review-agent.md +8 -1
- package/kit/agents/crew-security-expert.md +4 -3
- package/kit/agents/crew-test-expert.md +6 -2
- package/kit/eval/doctor.sh +201 -1
- package/kit/eval/gate-report.sh +28 -0
- package/kit/eval/golden-holdout.txt +2 -0
- package/kit/eval/golden-routing.txt +17 -0
- package/kit/eval/lib/crew-map/contracts.mjs +77 -0
- package/kit/eval/lib/crew-map/crew-map.sh +2 -1
- package/kit/eval/lib/crew-map/detect.mjs +2 -1
- package/kit/eval/lib/crew-map/narrative.mjs +14 -3
- package/kit/eval/lib/crew-map/project.mjs +45 -6
- package/kit/eval/lib/crew-map/scan.mjs +153 -14
- package/kit/eval/lib/findings/findings.schema.json +11 -1
- package/kit/eval/lib/findings/findings.sh +24 -1
- package/kit/eval/lib/hook-inject.sh +159 -0
- package/kit/eval/lib/lockfiles.sh +71 -0
- package/kit/eval/lib/payload-check.sh +29 -0
- package/kit/eval/lib/preview.sh +3 -3
- package/kit/eval/lib/review-bench/bench.mjs +14 -2
- package/kit/eval/lib/review-prepass/prepass.mjs +32 -3
- package/kit/eval/lib/settings-json.awk +18 -0
- package/kit/eval/lib/untrusted-text.awk +38 -0
- package/kit/eval/scan-skill.sh +67 -20
- package/kit/eval/smoke-test.sh +1700 -40
- package/kit/eval/utilization.sh +77 -3
- package/kit/hooks/agent-outcome.sh +9 -1
- package/kit/hooks/board-sync.sh +49 -3
- package/kit/hooks/board.sh +8 -8
- package/kit/hooks/branch-fresh.sh +101 -0
- package/kit/hooks/floor-blocklist.txt +19 -1
- package/kit/hooks/guard-bash.sh +92 -8
- package/kit/hooks/guard-question.sh +2 -1
- package/kit/hooks/loop-guard.sh +445 -0
- package/kit/hooks/map-stale.sh +437 -0
- package/kit/hooks/pre-commit +48 -7
- package/kit/hooks/precompact-snapshot.sh +102 -6
- package/kit/hooks/prompt-approval.sh +45 -9
- package/kit/hooks/route-hint.sh +36 -7
- package/kit/hooks/secret-blocklist.txt +55 -1
- package/kit/hooks/session-guard.sh +45 -15
- package/kit/hooks/session-rehydrate.sh +34 -11
- package/kit/hooks/session-stats.sh +169 -8
- package/kit/hooks/session-update-check.sh +5 -1
- package/kit/hooks/skill-trust.sh +23 -14
- package/kit/hooks/turn-check.sh +190 -0
- package/kit/owned-blobs.tsv +4 -4
- package/kit/settings.json +64 -0
- package/kit/skills/a11y/SKILL.md +50 -3
- package/kit/skills/a11y/references/recipes.md +41 -0
- package/kit/skills/adr/SKILL.md +14 -2
- package/kit/skills/api-design/SKILL.md +6 -1
- package/kit/skills/api-design/references/idempotency.md +39 -0
- package/kit/skills/brainstorm/SKILL.md +4 -2
- package/kit/skills/brainstorm/references/asking.md +47 -0
- package/kit/skills/ci-pipeline/SKILL.md +11 -1
- package/kit/skills/ci-pipeline/references/agent-job.md +33 -0
- package/kit/skills/commit-message/SKILL.md +9 -3
- package/kit/skills/confidence-check/SKILL.md +9 -7
- package/kit/skills/confidence-check/references/source-check.md +37 -0
- package/kit/skills/crew-approve/SKILL.md +3 -0
- package/kit/skills/crew-audit/SKILL.md +63 -0
- package/kit/skills/crew-board/SKILL.md +2 -2
- package/kit/skills/crew-code-review/SKILL.md +27 -4
- package/kit/skills/crew-code-review/references/panel-mode.md +9 -9
- package/kit/skills/crew-code-review/references/simplify.md +28 -0
- package/kit/skills/crew-doctor/SKILL.md +3 -2
- package/kit/skills/crew-gates/SKILL.md +3 -0
- package/kit/skills/crew-gates/references/enforcers.md +30 -0
- package/kit/skills/crew-interview/SKILL.md +42 -0
- package/kit/skills/crew-map/SKILL.md +26 -6
- package/kit/skills/crew-plan/SKILL.md +9 -2
- package/kit/skills/crew-pr/SKILL.md +57 -0
- package/kit/skills/crew-pr/references/checks.md +35 -0
- package/kit/skills/crew-pr/references/threads.md +23 -0
- package/kit/skills/crew-review/SKILL.md +34 -1
- package/kit/skills/crew-ship/SKILL.md +5 -2
- package/kit/skills/crew-skill/SKILL.md +26 -1
- package/kit/skills/crew-update/SKILL.md +4 -1
- package/kit/skills/db-migration/SKILL.md +15 -0
- package/kit/skills/db-migration/references/expand-contract.md +52 -0
- package/kit/skills/dependency-audit/SKILL.md +34 -1
- package/kit/skills/dependency-audit/scripts/record.sh +37 -0
- package/kit/skills/dependency-upgrade/SKILL.md +29 -1
- package/kit/skills/deploy/SKILL.md +18 -0
- package/kit/skills/deploy/references/topology-a.md +7 -0
- package/kit/skills/deploy/references/topology-b.md +2 -2
- package/kit/skills/docs-writer/SKILL.md +37 -2
- package/kit/skills/eval-grader/SKILL.md +9 -0
- package/kit/skills/eval-grader/references/method.md +26 -0
- package/kit/skills/frontend/SKILL.md +5 -2
- package/kit/skills/frontend/references/from-design.md +29 -0
- package/kit/skills/frontend/references/page-metadata.md +17 -0
- package/kit/skills/frontend/references/verify-contract.md +18 -1
- package/kit/skills/frontend/references/worst-data.md +35 -0
- package/kit/skills/frontend-design/SKILL.md +20 -4
- package/kit/skills/frontend-design/references/design-review.md +21 -0
- package/kit/skills/frontend-design/references/detection.md +44 -0
- package/kit/skills/frontend-design/references/motion.md +54 -0
- package/kit/skills/frontend-design/references/ui-copy.md +35 -0
- package/kit/skills/frontend-rn-expo/SKILL.md +3 -0
- package/kit/skills/handoff/SKILL.md +28 -3
- package/kit/skills/handoff/references/cold-reader.md +13 -6
- package/kit/skills/i18n-integrity/SKILL.md +3 -0
- package/kit/skills/iterate/SKILL.md +7 -2
- package/kit/skills/mcp-builder/SKILL.md +21 -4
- package/kit/skills/mcp-builder/references/building.md +74 -13
- package/kit/skills/mcp-builder/references/cli-for-agents.md +26 -0
- package/kit/skills/observability/SKILL.md +13 -1
- package/kit/skills/performance/SKILL.md +25 -1
- package/kit/skills/performance/references/bottlenecks.md +11 -0
- package/kit/skills/performance/references/web-vitals.md +31 -0
- package/kit/skills/red-team/SKILL.md +25 -3
- package/kit/skills/reflect/SKILL.md +7 -2
- package/kit/skills/release/SKILL.md +13 -0
- package/kit/skills/security-scan/SKILL.md +6 -2
- package/kit/skills/security-scan/references/ai-agents.md +16 -0
- package/kit/skills/security-scan/references/fronts.md +59 -2
- package/kit/skills/security-scan/references/reporting.md +13 -0
- package/kit/skills/security-scan/references/verify.md +9 -0
- package/kit/skills/sonarqube-check/SKILL.md +32 -2
- package/kit/skills/sonarqube-check/references/ratchet.md +32 -0
- package/kit/skills/spec-planning/SKILL.md +25 -8
- package/kit/skills/systematic-debugging/SKILL.md +15 -7
- package/kit/skills/systematic-debugging/references/techniques.md +5 -0
- package/kit/skills/teamboard/SKILL.md +3 -3
- package/kit/skills/testing/SKILL.md +18 -3
- package/kit/skills/testing/references/browser-headless.md +21 -0
- package/kit/skills/token-budget/SKILL.md +26 -5
- package/kit/skills/worktree/SKILL.md +13 -5
- package/kit/studio/server/lib/session.js +23 -2
- package/kit/studio/server/lib/worktree-changes.js +64 -0
- package/kit/studio/web/convo.js +14 -0
- package/kit/studio/web/map-plan.js +54 -8
- package/kit/studio/web/map.js +15 -3
- package/package.json +5 -4
- package/start.sh +11 -2
|
@@ -315,6 +315,14 @@ export function inspectOf(node, doc, edges, findings) {
|
|
|
315
315
|
other: node.structure?.otherFiles ?? 0,
|
|
316
316
|
tests: node.structure?.testFiles ?? 0,
|
|
317
317
|
} : null,
|
|
318
|
+
// Where its tests are (its own test files and a test project named for it), how often it changed in the commits
|
|
319
|
+
// the scan read, and the WHY/HACK/FIXME lines in its code: what someone about to change it asks first.
|
|
320
|
+
testFiles: Array.isArray(node.tests?.files) ? node.tests.files.filter((f) => typeof f === 'string') : [],
|
|
321
|
+
testTotal: Number.isInteger(node.tests?.total) ? node.tests.total : 0,
|
|
322
|
+
changed: Number.isInteger(node.commits) && Number.isInteger(doc?.source?.commitsRead) && doc.source.commitsRead > 0
|
|
323
|
+
? `Changed in ${node.commits} of the last ${doc.source.commitsRead} ${doc.source.commitsRead === 1 ? 'commit' : 'commits'}` : null,
|
|
324
|
+
notes: (node.markers?.evidence ?? []).filter((e) => e && typeof e.file === 'string').map((e) => ({ at: `${e.file}:${e.line}`, text: String(e.text ?? '') })),
|
|
325
|
+
notesTotal: node.markers?.evidenceTotal ?? (node.markers?.evidence ?? []).length,
|
|
318
326
|
connectsTo: out,
|
|
319
327
|
connections: { out, in: into },
|
|
320
328
|
byKind: Object.entries(byKind).sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0)),
|
|
@@ -385,23 +393,61 @@ export function layoutOf(nodes, { width = 960, chips = {}, rowKey = null } = {})
|
|
|
385
393
|
return { bands, pos, width: Math.max(width, right + GAP_X), height: y };
|
|
386
394
|
}
|
|
387
395
|
|
|
388
|
-
/**
|
|
389
|
-
|
|
396
|
+
/**
|
|
397
|
+
* A line between two cards: out of the bottom of the upper one into the top of the lower, or side to side.
|
|
398
|
+
* `pa` and `pb` say where along its side the line leaves `a` and enters `b`, as a fraction of that side (½ = the
|
|
399
|
+
* middle); `routesOf` spreads them so lines that share a side do not share a pixel.
|
|
400
|
+
*/
|
|
401
|
+
export function pathOf(a, b, pa = 0.5, pb = 0.5) {
|
|
390
402
|
if (!a || !b) return null;
|
|
391
403
|
const down = b.y >= a.y + a.h;
|
|
392
404
|
const up = a.y >= b.y + b.h;
|
|
393
405
|
if (down || up) {
|
|
394
|
-
const [s, t] = down ? [a, b] : [b, a];
|
|
395
|
-
const x1 = s.x + s.w
|
|
406
|
+
const [s, t, fs, ft] = down ? [a, b, pa, pb] : [b, a, pb, pa];
|
|
407
|
+
const x1 = s.x + s.w * fs; const y1 = s.y + s.h; const x2 = t.x + t.w * ft; const y2 = t.y;
|
|
396
408
|
const m = (y1 + y2) / 2;
|
|
397
409
|
return { d: `M${x1} ${y1} C${x1} ${m} ${x2} ${m} ${x2} ${y2}`, mid: [(x1 + x2) / 2, m] };
|
|
398
410
|
}
|
|
399
|
-
const [s, t] = a.x <= b.x ? [a, b] : [b, a];
|
|
400
|
-
const x1 = s.x + s.w; const y1 = s.y + s.h
|
|
401
|
-
|
|
411
|
+
const [s, t, fs, ft] = a.x <= b.x ? [a, b, pa, pb] : [b, a, pb, pa];
|
|
412
|
+
const x1 = s.x + s.w; const y1 = s.y + s.h * fs; const x2 = t.x; const y2 = t.y + t.h * ft;
|
|
413
|
+
const mx = (x1 + x2) / 2;
|
|
414
|
+
// Level ends are one straight line; ends at two heights turn square halfway, so no line runs on a slant.
|
|
415
|
+
if (y1 === y2) return { d: `M${x1} ${y1} L${x2} ${y2}`, mid: [mx, y1] };
|
|
416
|
+
return { d: `M${x1} ${y1} H${mx} V${y2} H${x2}`, mid: [mx, (y1 + y2) / 2] };
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
/**
|
|
420
|
+
* Every edge's line, with the lines that leave or enter one side of one card spread along it: the k-th of N at
|
|
421
|
+
* k/(N+1), ranked by where the other end sits, so neighbours do not cross. Measured on the crew-map-test fixtures and
|
|
422
|
+
* Crewforth's own map before this: 48 line ends shared a pixel with another across 46 edges, so a card with three
|
|
423
|
+
* dependents showed one line. A side with one line keeps the middle, as before.
|
|
424
|
+
*/
|
|
425
|
+
export function routesOf(edges, pos) {
|
|
426
|
+
const sides = new Map();
|
|
427
|
+
const add = (key, i, c) => { if (!sides.has(key)) sides.set(key, []); sides.get(key).push({ i, c }); };
|
|
428
|
+
const geo = edges.map((e, i) => {
|
|
429
|
+
const a = pos[e.from]; const b = pos[e.to];
|
|
430
|
+
if (!a || !b) return null;
|
|
431
|
+
const vertical = b.y >= a.y + a.h || a.y >= b.y + b.h;
|
|
432
|
+
if (vertical) {
|
|
433
|
+
const aBelow = a.y >= b.y + b.h;
|
|
434
|
+
const ka = `${e.from}:${aBelow ? 'top' : 'bottom'}`; const kb = `${e.to}:${aBelow ? 'bottom' : 'top'}`;
|
|
435
|
+
add(ka, i, b.x + b.w / 2); add(kb, i, a.x + a.w / 2);
|
|
436
|
+
return { a, b, ka, kb };
|
|
437
|
+
}
|
|
438
|
+
const aLeft = a.x <= b.x;
|
|
439
|
+
const ka = `${e.from}:${aLeft ? 'right' : 'left'}`; const kb = `${e.to}:${aLeft ? 'left' : 'right'}`;
|
|
440
|
+
add(ka, i, b.y + b.h / 2); add(kb, i, a.y + a.h / 2);
|
|
441
|
+
return { a, b, ka, kb };
|
|
442
|
+
});
|
|
443
|
+
const at = new Map();
|
|
444
|
+
for (const [key, list] of sides) {
|
|
445
|
+
list.sort((p, q) => p.c - q.c || p.i - q.i);
|
|
446
|
+
list.forEach((p, k) => at.set(`${key}|${p.i}`, (k + 1) / (list.length + 1)));
|
|
447
|
+
}
|
|
448
|
+
return geo.map((g, i) => (g ? pathOf(g.a, g.b, at.get(`${g.ka}|${i}`), at.get(`${g.kb}|${i}`)) : null));
|
|
402
449
|
}
|
|
403
450
|
|
|
404
|
-
/** The endpoint chips of a module, as the Endpoints layer lists them: what it provides, then what it calls. */
|
|
405
451
|
export function chipsOf(node, doc) {
|
|
406
452
|
const p = (doc.provides?.endpoints ?? []).filter((e) => e.module === node.id).map((e) => `${e.method} ${e.path}`);
|
|
407
453
|
const c = (doc.consumes?.endpoints ?? []).filter((e) => e.module === node.id).map((e) => `→ ${e.method} ${e.path}`);
|
package/kit/studio/web/map.js
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
// nothing; what leaves the page is copied text: a finding as a task, or a file:line.
|
|
11
11
|
import {
|
|
12
12
|
nodesOf, edgesOf, edgeKey, litEdges, findingsOf, findingCounts, cardSub, summaryOf, sourceOf, inspectOf, taskOf,
|
|
13
|
-
emptyNote, layoutOf,
|
|
13
|
+
emptyNote, layoutOf, routesOf, chipsOf, inferredOnly, groupsOf, foldView, placed, BANDS, cardOf, tourOf, searchOf, resourceWord,
|
|
14
14
|
} from './map-plan.js';
|
|
15
15
|
import { Viewport, draggable, swallowClick } from './viewport.js';
|
|
16
16
|
|
|
@@ -231,8 +231,9 @@ export class MapView {
|
|
|
231
231
|
}
|
|
232
232
|
const lines = svg('svg', { class: 'mp-lines', width: lay.width, height: lay.height, 'aria-hidden': 'true' });
|
|
233
233
|
const labels = [];
|
|
234
|
-
|
|
235
|
-
|
|
234
|
+
const routes = routesOf(edges, lay.pos);
|
|
235
|
+
for (const [ei, e] of edges.entries()) {
|
|
236
|
+
const p = routes[ei];
|
|
236
237
|
if (!p) continue;
|
|
237
238
|
const path = svg('path', { d: p.d, class: 'mp-line' });
|
|
238
239
|
path.dataset.solid = String(e.solid);
|
|
@@ -495,6 +496,17 @@ export class MapView {
|
|
|
495
496
|
if (v.inside.other) sec.append(mk('p', 'sub', `${v.inside.other} more files in other folders`));
|
|
496
497
|
if (v.inside.tests) sec.append(mk('p', 'sub', `${v.inside.tests} test ${v.inside.tests === 1 ? 'file' : 'files'}`));
|
|
497
498
|
}
|
|
499
|
+
if (v.changed) sec.append(mk('p', 'sub', v.changed));
|
|
500
|
+
if (v.testFiles.length) {
|
|
501
|
+
sec.append(mk('span', 'lbl', `Tests · ${v.testTotal}`));
|
|
502
|
+
for (const f of v.testFiles) { const r = mk('div', 'mp-conn mp-inside'); r.append(mk('span', 'mp-file', f)); sec.append(r); }
|
|
503
|
+
if (v.testTotal > v.testFiles.length) sec.append(mk('p', 'sub', `${v.testTotal - v.testFiles.length} more in the map file`));
|
|
504
|
+
}
|
|
505
|
+
if (v.notes.length) {
|
|
506
|
+
sec.append(mk('span', 'lbl', `Notes in the code · ${v.notesTotal}`));
|
|
507
|
+
for (const x of v.notes) { const r = mk('div', 'mp-conn mp-inside'); r.append(this.#cite(x.at), mk('span', 'mp-ev', x.text)); sec.append(r); }
|
|
508
|
+
if (v.notesTotal > v.notes.length) sec.append(mk('p', 'sub', `${v.notesTotal - v.notes.length} more in the map file`));
|
|
509
|
+
}
|
|
498
510
|
sec.append(mk('span', 'lbl', 'Connects to'));
|
|
499
511
|
if (!v.connectsTo.length) sec.append(mk('p', 'sub', 'Nothing on this map.'));
|
|
500
512
|
for (const c of v.connectsTo) sec.append(this.#conn(c));
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "crewforth",
|
|
3
|
-
"version": "3.
|
|
4
|
-
"description": "Crewforth
|
|
3
|
+
"version": "3.5.0-rc.1",
|
|
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,7 +43,7 @@
|
|
|
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",
|
package/start.sh
CHANGED
|
@@ -33,6 +33,15 @@ if [ "$_HELP_ONLY" = 0 ] && [ ! -d "$SRC" ]; then
|
|
|
33
33
|
echo "start.sh and kit/ must be in the SAME directory (both come together when you unzip)."
|
|
34
34
|
exit 1
|
|
35
35
|
fi
|
|
36
|
+
# A payload that lost files (a truncated archive, a folder dropped in a copy) is refused before the first write, so
|
|
37
|
+
# a broken download says so instead of installing gates that fail on every call. English, like the check above: it
|
|
38
|
+
# answers before the language is chosen. eval/lib/payload-check.sh says what it reads.
|
|
39
|
+
if [ "$_HELP_ONLY" = 0 ] && [ "${CREW_PAYLOAD_UNCHECKED:-0}" != 1 ] && [ -f "$SRC/eval/lib/payload-check.sh" ]; then
|
|
40
|
+
_pc="$(bash "$SRC/eval/lib/payload-check.sh" "$SRC" 2>&1)" || {
|
|
41
|
+
echo "ERROR: the kit/ payload is incomplete — nothing installed:"; printf '%s\n' "$_pc" | sed 's/^/ /'
|
|
42
|
+
echo "Download it again (npx crewforth@latest, or a fresh archive). CREW_PAYLOAD_UNCHECKED=1 installs it anyway."
|
|
43
|
+
exit 1; }
|
|
44
|
+
fi
|
|
36
45
|
|
|
37
46
|
# Refuse to run inside a checkout of the kit's own source repository. This script ends by deleting
|
|
38
47
|
# kit/ and itself, which is correct when the kit has been unpacked into a project and is being
|
|
@@ -569,7 +578,7 @@ count_installed() { # $1=glob -> count to install
|
|
|
569
578
|
}
|
|
570
579
|
N_AG="$(count_installed "$SRC/agents/*.md")"
|
|
571
580
|
# Skills and commands the way the README and crewforth.com count them, so the install does not print a third number:
|
|
572
|
-
# a skill whose metadata says `kind: command` is a command, one marked `experimental: true` is neither (it is
|
|
581
|
+
# a skill whose metadata says `kind: command` is a command, one marked `experimental: "true"` is neither (it is
|
|
573
582
|
# installed and works when typed, but nothing advertises it). Read from the frontmatter with builtins only.
|
|
574
583
|
count_showcase() { # $1 = a skills directory -> N_SKL N_CMD
|
|
575
584
|
N_SKL=0; N_CMD=0; local f l k e d
|
|
@@ -577,7 +586,7 @@ count_showcase() { # $1 = a skills directory -> N_SKL N_CMD
|
|
|
577
586
|
[ -f "$f" ] || continue; k=0; e=0; d=0
|
|
578
587
|
while IFS= read -r l || [ -n "$l" ]; do
|
|
579
588
|
l="${l%$'\r'}"
|
|
580
|
-
case "$l" in ---) d=$((d+1)); [ "$d" -ge 2 ] && break ;; " kind: command") k=1 ;; " experimental: true") e=1 ;; esac
|
|
589
|
+
case "$l" in ---) d=$((d+1)); [ "$d" -ge 2 ] && break ;; " kind: command") k=1 ;; " experimental: true"|" experimental: \"true\"") e=1 ;; esac
|
|
581
590
|
done < "$f"
|
|
582
591
|
[ "$e" = 1 ] && continue
|
|
583
592
|
if [ "$k" = 1 ]; then N_CMD=$((N_CMD+1)); else N_SKL=$((N_SKL+1)); fi
|