From 55384e5b39f3738777e8833a83ebfa4026ff065e Mon Sep 17 00:00:00 2001 From: Kjell Tore Guttormsen Date: Sat, 9 May 2026 09:22:01 +0200 Subject: [PATCH] =?UTF-8?q?feat(voyage):=20add=20--profile=20valued=20flag?= =?UTF-8?q?=20to=20arg-parser=20FLAG=5FSCHEMA=20=E2=80=94=20v4.1=20SC=20#4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Step 2 av v4.1-execute (Wave 1, Session 1). Legg --profile i valued-arrayen for alle 6 voyage-kommandoer (trekbrief, trekresearch, trekplan, trekexecute, trekreview, trekcontinue). Mønster identisk med eksisterende --project/--brief valued-handling. Ingen endring til parseArgs-logikk — utvider kun schema. Tester (11 nye, baseline 361 → 372): - 6 happy-path-tests (én per kommando) - ARG_MISSING_VALUE for --profile uten verdi - --profile + --quick kombo - --profile + --gates edge-case (--gates parses inline, ikke i FLAG_SCHEMA) - --profile + --project kombo - trekcontinue --profile (validerer at tomt valued[] nå er utvidet) Co-Authored-By: Claude Opus 4.7 --- plugins/voyage/lib/parsers/arg-parser.mjs | 12 ++--- .../tests/parsers/arg-parser-profile.test.mjs | 53 +++++++++++++++++++ 2 files changed, 59 insertions(+), 6 deletions(-) create mode 100644 plugins/voyage/tests/parsers/arg-parser-profile.test.mjs diff --git a/plugins/voyage/lib/parsers/arg-parser.mjs b/plugins/voyage/lib/parsers/arg-parser.mjs index 7dbafd3..c843eb1 100644 --- a/plugins/voyage/lib/parsers/arg-parser.mjs +++ b/plugins/voyage/lib/parsers/arg-parser.mjs @@ -7,33 +7,33 @@ const FLAG_SCHEMA = { trekbrief: { boolean: ['--quick', '--fg'], - valued: [], + valued: ['--profile'], aliases: {}, }, trekresearch: { boolean: ['--quick', '--local', '--external', '--fg'], - valued: ['--project'], + valued: ['--project', '--profile'], aliases: {}, }, trekplan: { boolean: ['--quick', '--fg'], - valued: ['--project', '--brief', '--export', '--decompose'], + valued: ['--project', '--brief', '--export', '--decompose', '--profile'], multi: ['--research'], aliases: {}, }, trekexecute: { boolean: ['--resume', '--dry-run', '--validate', '--fg'], - valued: ['--project', '--step', '--session'], + valued: ['--project', '--step', '--session', '--profile'], aliases: {}, }, trekreview: { boolean: ['--quick', '--fg', '--dry-run', '--validate'], - valued: ['--project', '--since'], + valued: ['--project', '--since', '--profile'], aliases: {}, }, trekcontinue: { boolean: ['--help', '--cleanup', '--confirm', '--dry-run'], - valued: [], + valued: ['--profile'], aliases: {}, }, }; diff --git a/plugins/voyage/tests/parsers/arg-parser-profile.test.mjs b/plugins/voyage/tests/parsers/arg-parser-profile.test.mjs new file mode 100644 index 0000000..7224341 --- /dev/null +++ b/plugins/voyage/tests/parsers/arg-parser-profile.test.mjs @@ -0,0 +1,53 @@ +// tests/parsers/arg-parser-profile.test.mjs +// SC #4: --profile valued flag MUST be recognized on all 6 voyage commands. + +import { test } from 'node:test'; +import { strict as assert } from 'node:assert'; +import { parseArgs } from '../../lib/parsers/arg-parser.mjs'; + +const COMMANDS = ['trekbrief', 'trekresearch', 'trekplan', 'trekexecute', 'trekreview', 'trekcontinue']; + +for (const cmd of COMMANDS) { + test(`${cmd} — --profile economy parses as valued`, () => { + const r = parseArgs('--profile economy', cmd); + assert.equal(r.flags['--profile'], 'economy', `${cmd} should accept --profile economy`); + assert.equal(r.errors.length, 0, `${cmd} should have no errors`); + assert.equal(r.unknown.length, 0, `${cmd} should not mark --profile as unknown`); + }); +} + +test('trekplan — --profile without value emits ARG_MISSING_VALUE', () => { + const r = parseArgs('--profile', 'trekplan'); + const missing = r.errors.find((e) => e.code === 'ARG_MISSING_VALUE'); + assert.ok(missing, 'must surface ARG_MISSING_VALUE'); + assert.match(missing.message, /--profile/); +}); + +test('trekplan — --profile economy --quick combines correctly', () => { + const r = parseArgs('--profile economy --quick', 'trekplan'); + assert.equal(r.flags['--profile'], 'economy'); + assert.equal(r.flags['--quick'], true); +}); + +test('trekplan — --profile economy --gates open: --gates is unknown (parsed inline by command prose, not in FLAG_SCHEMA)', () => { + // Edge case from plan.md Step 2 (per plan-critic minor): --gates is intentionally + // NOT in FLAG_SCHEMA; commands parse it inline. Verify --profile still parses cleanly + // and --gates ends up in unknown[] / positional[] rather than colliding with --profile. + const r = parseArgs('--profile economy --gates open', 'trekplan'); + assert.equal(r.flags['--profile'], 'economy'); + // --gates is unknown to FLAG_SCHEMA; it lands in unknown[] and 'open' becomes positional + assert.ok(r.unknown.includes('--gates'), `expected --gates in unknown, got: ${JSON.stringify(r.unknown)}`); + assert.ok(r.positional.includes('open'), `expected 'open' as positional, got: ${JSON.stringify(r.positional)}`); +}); + +test('trekexecute — --profile balanced --project /tmp/p combines correctly', () => { + const r = parseArgs('--profile balanced --project /tmp/p', 'trekexecute'); + assert.equal(r.flags['--profile'], 'balanced'); + assert.equal(r.flags['--project'], '/tmp/p'); +}); + +test('trekcontinue — --profile premium parses without --project', () => { + // trekcontinue had empty valued[] before v4.1 — sanity check the array is now extended + const r = parseArgs('--profile premium', 'trekcontinue'); + assert.equal(r.flags['--profile'], 'premium'); +});