Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ Each release of Research-Kit, newest first. The version is `KIT_VERSION` in

## Unreleased

- `collect-remote` refuses empty repository, topic, client-ref, prior and prefer
values by name before creating an output directory or reading a token (#287).

- ZIP archives declare UTF-8 names in both headers, so ordinary extractors preserve non-ASCII paths declared by the package manifest (#345).

- Machine config saves preserve unpatched raw role and posture values, including typos
Expand Down
6 changes: 6 additions & 0 deletions docs/ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,12 @@ about defects that were already fixed. Nothing was deleted; it was moved and lin

## Search and collection invocation

`bin/collect-remote.mjs` applies the existing value checker to `--repository`, `--topic`,
`--client-ref`, `--prior` and `--prefer`, as well as its workflow and budget flags.
An empty equals/separate value or bare optional value flag is refused by name with
exit 3 before output-directory creation, token lookup or dispatch (#287). Absent
required flags keep their existing refusal, including the repository-only pickup path.

The CLI chooses providers before invoking its coordinator. `transport.mjs` returns the fetch adapter, search adapter or merged adapters, selection reasons, and selection readiness metadata. Automatic fetch selection may perform a memoized Firecrawl CLI `--status` probe when the executable is present. Selection does not search or fetch a page. The coordinators decide which queries and pages to attempt; the shared search session and collection writer carry out those decisions.

```mermaid
Expand Down
2 changes: 1 addition & 1 deletion research-kit/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -568,7 +568,7 @@ node research-kit/bin/selftest.mjs # all of it
node research-kit/bin/selftest.mjs gate hook # just these files
```

1845 tests, offline, no key and no network. The runner **awaits** every test, so `ok` means
1846 tests, offline, no key and no network. The runner **awaits** every test, so `ok` means
the assertions settled (ADR-0021), and each test is raced against a watchdog
(`RESEARCH_KIT_TEST_TIMEOUT`, default 60s).

Expand Down
5 changes: 1 addition & 4 deletions research-kit/bin/collect-remote.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -150,12 +150,9 @@ checkFlagValues(flags, {
'search-transport': { choices: ['auto', 'serpapi', 'firecrawl-cli'] },
timeout: { int: true, min: 1 },
out: {}, workflow: {}, ref: {},
repository: {}, topic: {}, 'client-ref': {}, prior: {}, prefer: {},
}, { exit: EXIT.CANNOT_START });

if (flags['client-ref'] === true) {
process.stderr.write('--client-ref needs a value\n');
process.exit(EXIT.CANNOT_START);
}
const clientReference = checkClientRef(flags['client-ref']);
if (!clientReference.ok) {
process.stderr.write(`${redact(clientReference.detail)}\n`);
Expand Down
20 changes: 19 additions & 1 deletion research-kit/test/cli.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ test('collect-remote refuses unsafe client references before token lookup or cre
const bare = run('collect-remote.mjs', ['--repository', 'o/r', '--topic', 't', '--client-ref'], { root });
assert.equal(bare.status, 3);
assert.match(bare.err, /--client-ref needs a value/);
for (const clientRef of ['', 'job-1.a_b', 'a'.repeat(64)]) {
for (const clientRef of ['job-1.a_b', 'a'.repeat(64)]) {
const r = run('collect-remote.mjs', ['--repository', 'o/r', '--topic', 't', '--client-ref', clientRef, '--no-wait'], { root });
assert.equal(r.status, 3);
assert.match(r.err, /no GitHub token/, 'valid input must reach the existing missing-token refusal');
Expand Down Expand Up @@ -841,6 +841,24 @@ test('collect-remote refuses a bare --out, --workflow or --ref before it creates
}
});

test('collect-remote refuses empty required and optional values before token lookup or creating out', () => {
for (const flag of ['repository', 'topic', 'client-ref', 'prior', 'prefer']) {
const required = flag === 'repository' ? ['--topic', 't']
: flag === 'topic' ? ['--repository', 'o/r'] : ['--repository', 'o/r', '--topic', 't'];
const spellings = [[`--${flag}=`], [`--${flag}`, '']];
if (!['repository', 'topic'].includes(flag)) spellings.push([`--${flag}`]);
for (const spelling of spellings) {
const root = project();
const out = path.join(root, 'not-created');
const r = run('collect-remote.mjs', [...required, '--out', out, ...spelling], { root });
assert.equal(r.status, 3, r.all);
assert.equal(r.err.split('\n')[0], `--${flag} needs a value`, r.all);
assert.doesNotMatch(r.all, /no GitHub token/);
assert.equal(fs.existsSync(out), false, 'invalid flags must not create the output directory');
}
}
});

// Found 2026-10-01: lib/dispatch.mjs told the caller to "retry with --run-id <n>", exit 4 said
// "the run id is on stdout", and collect-remote had no --run-id - it refused it as an unknown
// option. A watch that ended (a timeout, a dropped connection, a closed laptop) could not be
Expand Down
Loading