mirror of
https://github.com/garrytan/gstack.git
synced 2026-11-14 20:37:14 +01:00
* Keep the scroll selector when --wait is absent Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * Skip a PATH browse that links to another program such as xdg-open Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * Give each project its own browse slug on installs without ~/.claude Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * Keep a question marker when its signal hint is malformed Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * Read the lowercased question id in the never-ask preference hook Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * Keep a marker's tail in the one-way door check Review-Finding: p1/targeted#1 reader=targeted Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * Keep a marker's tail apart from the next word in the one-way door check Review-Finding: p2/outside-voice#1 reader=outside-voice Review-Finding: p2/adversarial-native#1 reader=adversarial-native Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * Say where old domain skills live and narrow the marker note in the changelog Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * Say how the browse daemon picks a project's domain skill file Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> --------- Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
57 lines
2.6 KiB
TypeScript
57 lines
2.6 KiB
TypeScript
import { describe, expect, test } from 'bun:test';
|
|
import { parseQidMarker } from '../scripts/qid-marker';
|
|
import { resolveHintedOptionKey, signalKeyLines } from '../scripts/psychographic-signals';
|
|
|
|
describe('parseQidMarker (#3442)', () => {
|
|
test('reads a plain marker and strips it', () => {
|
|
expect(parseQidMarker('D1 — Ship? <gstack-qid:ship-test-failure-triage>')).toEqual({ id: 'ship-test-failure-triage', stripped: 'D1 — Ship?' });
|
|
});
|
|
|
|
test('reads a signal hint and strips the whole marker', () => {
|
|
expect(parseQidMarker('Add caching? <gstack-qid:plan-ceo-review-add-caching;signal=scope-appetite>')).toEqual({
|
|
id: 'plan-ceo-review-add-caching',
|
|
signal_key: 'scope-appetite',
|
|
stripped: 'Add caching?',
|
|
});
|
|
});
|
|
|
|
test('lowercases an uppercase marker', () => {
|
|
expect(parseQidMarker('<gstack-qid:Plan-CEO-X;signal=Scope-Appetite> q')).toMatchObject({ id: 'plan-ceo-x', signal_key: 'scope-appetite' });
|
|
});
|
|
|
|
test('a malformed signal hint drops only the hint; the id still names the question', () => {
|
|
expect(parseQidMarker('Q? <gstack-qid:plan-x;signal=scope_appetite>')).toEqual({ id: 'plan-x', stripped: 'Q?' });
|
|
expect(parseQidMarker('Q? <gstack-qid:plan-x;signal=>')).toEqual({ id: 'plan-x', stripped: 'Q?' });
|
|
expect(parseQidMarker('Q? <gstack-qid:plan-x;signal=scope appetite>')).toEqual({ id: 'plan-x', stripped: 'Q?' });
|
|
expect(parseQidMarker('Q? <gstack-qid:plan-x;signl=scope-appetite>')).toEqual({ id: 'plan-x', stripped: 'Q?' });
|
|
});
|
|
|
|
test('no marker returns undefined', () => {
|
|
expect(parseQidMarker('plain question')).toBeUndefined();
|
|
});
|
|
});
|
|
|
|
describe('resolveHintedOptionKey (#3442)', () => {
|
|
test('an exact option key passes through', () => {
|
|
expect(resolveHintedOptionKey('scope-appetite', 'expand')).toBe('expand');
|
|
});
|
|
|
|
test('a label that starts with the key words maps to the key', () => {
|
|
expect(resolveHintedOptionKey('scope-appetite', 'B) Reduce scope (recommended)')).toBe('reduce');
|
|
expect(resolveHintedOptionKey('architecture-care', 'Accept risk and move on')).toBe('accept-risk');
|
|
});
|
|
|
|
test('a cue-table word never maps, so a yes cannot invert a signal', () => {
|
|
expect(resolveHintedOptionKey('scope-appetite', 'Yes, cut it')).toBeUndefined();
|
|
expect(resolveHintedOptionKey('architecture-care', 'Fix it later')).toBeUndefined();
|
|
});
|
|
|
|
test('an unknown signal key maps nothing', () => {
|
|
expect(resolveHintedOptionKey('made-up', 'expand')).toBeUndefined();
|
|
});
|
|
|
|
test('signalKeyLines lists every signal with its option keys', () => {
|
|
expect(signalKeyLines()).toContain('architecture-care: fix-now | defer | accept-risk');
|
|
});
|
|
});
|