mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-10-04 14:39:42 +02:00
feat: skill fast-path hardening, lineage retune + colors, per-tab pop-out, reliable tab alerts
- SKILL.md: forbid the standalone preamble check and pre-spawn recon turns (measured: two wasted model turns cost ~12s of a 28s two-worker run; the hardened flow measured 20.2s cold / 12.8s warm end to end) - Lineage lines: dip now hangs from the strip's bottom edge (cap 104 -> 64, no stacked row offsets), fixing the deep bow in wrapped strips and keeping row-1 arcs off row-2 tab labels; per-child color palette (skin blue first, then matrix green, pink, violet, red, turquoise, orange) via an inline --lineage-color custom property - Session Options -> Session: per-TAB pop-out (open-in-window) button override on top of the general showTabDetachButton setting; per-device localStorage map rendered as the tab-show-detach class - Tab alerts: seed the pending-hook state machine from GET /api/approvals regardless of the approvals-inbox setting (reloads used to lose the red tab entirely with the inbox off), clear unconditionally on approval_resolved, and repaint the alert as a steady red/yellow ring + glow + status dot on a ::before overlay so it stays visible on the selected (active) tab until the permission is actually resolved - docs: worker warm-pool design sketch (verified numbers baked in) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -24,6 +24,7 @@ function loadLineageHelper() {
|
||||
DIP_MIN_PX: number;
|
||||
DIP_MAX_PX: number;
|
||||
SIBLING_STEP_PX: number;
|
||||
COLORS: string[];
|
||||
};
|
||||
}
|
||||
).CodemanLineage;
|
||||
@@ -61,8 +62,9 @@ describe('lineage line geometry', () => {
|
||||
const near = helper.computePath({ parent: tab(0), child: tab(140), strip: STRIP })!;
|
||||
const far = helper.computePath({ parent: tab(0), child: tab(1000), strip: STRIP })!;
|
||||
|
||||
const nearDip = controlYs(near.d)[0] - 34;
|
||||
const farDip = controlYs(far.d)[0] - 34;
|
||||
// The dip hangs from the STRIP's bottom edge (40), not the tab bottoms.
|
||||
const nearDip = controlYs(near.d)[0] - 40;
|
||||
const farDip = controlYs(far.d)[0] - 40;
|
||||
expect(farDip).toBeGreaterThan(nearDip);
|
||||
expect(nearDip).toBeGreaterThanOrEqual(helper.DIP_MIN_PX);
|
||||
expect(farDip).toBeLessThanOrEqual(helper.DIP_MAX_PX);
|
||||
@@ -80,15 +82,48 @@ describe('lineage line geometry', () => {
|
||||
it('keeps bending at strip-wide spans instead of flattening into a straight line', () => {
|
||||
const helper = loadLineageHelper();
|
||||
// A worker the agent skill starts is appended to the END of the strip, so this
|
||||
// is the span the feature is actually used at. The first shipped clamp (44px)
|
||||
// turned it into a flat thread across the terminal.
|
||||
// is the span the feature is actually used at. The corridor has failed in BOTH
|
||||
// directions: the first 44px clamp read as a flat thread here (#285), and the
|
||||
// 104px clamp that replaced it bowed deep into the terminal (2026-08-15), so this
|
||||
// pins the cap exactly rather than just a floor.
|
||||
const wide = helper.computePath({ parent: tab(0), child: tab(1300), strip: { ...STRIP, width: 1500 } })!;
|
||||
const near = helper.computePath({ parent: tab(0), child: tab(140), strip: STRIP })!;
|
||||
|
||||
const wideDip = controlYs(wide.d)[0] - 34;
|
||||
const nearDip = controlYs(near.d)[0] - 34;
|
||||
const wideDip = controlYs(wide.d)[0] - 40; // from the strip's bottom edge
|
||||
const nearDip = controlYs(near.d)[0] - 40;
|
||||
expect(wideDip).toBeGreaterThan(nearDip * 2);
|
||||
expect(wideDip).toBeGreaterThanOrEqual(80);
|
||||
expect(wideDip).toBe(helper.DIP_MAX_PX);
|
||||
expect(helper.DIP_MAX_PX).toBe(64);
|
||||
});
|
||||
|
||||
it('hangs the dip from the STRIP bottom, so no per-row offset ever stacks on it', () => {
|
||||
const helper = loadLineageHelper();
|
||||
const twoRowStrip = { left: 0, top: 0, width: 1200, height: 84 }; // rows at y 4-34 and 48-78
|
||||
// A wrapped pair (row 1 → row 2) and a same-row pair on ROW 1 of the same strip.
|
||||
const wrapped = helper.computePath({ parent: tab(0), child: tab(400, 48), strip: twoRowStrip })!;
|
||||
const row1Pair = helper.computePath({ parent: tab(0), child: tab(400), strip: twoRowStrip })!;
|
||||
|
||||
// Both brackets clear the ENTIRE strip: the wrapped one does not add the row
|
||||
// offset on top (the 2026-08-15 over-bow), and the row-1 pair does not draw
|
||||
// through row 2's tab labels (the retune's own first-draft regression).
|
||||
for (const geom of [wrapped, row1Pair]) {
|
||||
for (const y of controlYs(geom.d)) {
|
||||
expect(y).toBeGreaterThanOrEqual(84 + helper.DIP_MIN_PX);
|
||||
expect(y).toBeLessThanOrEqual(84 + helper.DIP_MAX_PX + helper.SIBLING_STEP_PX);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it('exposes a colour palette whose first entry defers to the skin blue', () => {
|
||||
const helper = loadLineageHelper();
|
||||
const colors = helper.COLORS;
|
||||
expect(Array.isArray(colors)).toBe(true);
|
||||
// '' = no override: session-lineage.js sets no inline --lineage-color and the
|
||||
// CSS falls back to the skin-tuned --session-blue, so a lone arc stays blue.
|
||||
expect(colors[0]).toBe('');
|
||||
expect(colors.length).toBeGreaterThanOrEqual(6);
|
||||
expect(new Set(colors).size).toBe(colors.length);
|
||||
for (const c of colors.slice(1)) expect(c).toMatch(/^#[0-9a-f]{6}$/i);
|
||||
});
|
||||
|
||||
it('brackets a wrapped pair BELOW the lower row rather than inside the row gap', () => {
|
||||
|
||||
Reference in New Issue
Block a user