Skip to content

Commit bec1e39

Browse files
committed
fix(rules): close the split-literal gap in no-unrouted-cli-invocation
The regex required a launcher in front of the package name, so a split literal (`"npx " + "@taskless/cli"`) put the two halves in separate string_fragment nodes and the rule never saw a match. It now matches the package name alone, which costs nothing: every string in packages/cli/src/ naming the package is an invocation, and both existing occurrences already sit inside applyCliInvocation(). Added a split-literal test case, which fails against the launcher-anchored regex. Both remaining limitations are documented in the rule's note rather than left implicit, since this rule is the only enforcement for some sites it covers: a split placed mid-name still evades any single-fragment rule, and an aliased import is not recognised as routed, which is a false positive and therefore the safe direction to fail in. Reported by review on #209.
1 parent ec077ed commit bec1e39

2 files changed

Lines changed: 20 additions & 1 deletion

File tree

‎.taskless/rules/sg/no-unrouted-cli-invocation/.tests/no-unrouted-cli-invocation-20260828-test.yml‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ invalid:
1515
console.log(
1616
"For humans: run `npx @taskless/cli` (no args) to install or update Taskless,"
1717
);
18+
- |
19+
const hint = "npx " + "@taskless/cli" + " init";
1820
- |
1921
const README_CONTENT = `## Usage
2022

‎.taskless/rules/sg/no-unrouted-cli-invocation/no-unrouted-cli-invocation.yml‎

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,31 @@ note: |
2424
Recipes in `src/agent/*.txt` are out of reach here by being .txt, which is
2525
correct: they carry a `<taskless-cli>` marker the reading agent fills in (see
2626
`src/prompts/recipes.ts`) and name no package at all.
27+
28+
TWO KNOWN LIMITATIONS, since this rule is the only enforcement for some of
29+
the sites it covers. Both are syntactic, and neither is reachable by
30+
anything in the tree today.
31+
32+
A SPLIT LITERAL puts the package name in its own fragment: `"npx " +
33+
"@taskless/cli"`. That is why the regex below matches the package name
34+
alone rather than requiring a launcher in front of it, which costs nothing
35+
because every string in `packages/cli/src/` naming the package is an
36+
invocation. A split placed mid-name (`"@taskless/" + "cli"`) still evades
37+
it, and no single-fragment rule can see that.
38+
39+
An ALIASED IMPORT (`import { applyCliInvocation as apply }`) is not
40+
recognised as routed, because the exemption matches the callee text. That
41+
direction is a FALSE POSITIVE: it reports a call that is already safe. Left
42+
as-is deliberately, since the failure is loud and the alternative would
43+
have the rule resolve imports.
2744
files:
2845
- "packages/cli/src/**"
2946
ignores:
3047
- "packages/cli/src/util/invocation.ts"
3148
- "packages/cli/src/util/package-manager.ts"
3249
rule:
3350
kind: string_fragment
34-
regex: "(npx|pnpm dlx|yarn dlx|bunx) @taskless/cli"
51+
regex: "@taskless/cli"
3552
not:
3653
inside:
3754
stopBy: end

0 commit comments

Comments
 (0)