Skip to content

Commit e593f2a

Browse files
committed
fix(cli): test the cross-pin case, rename the one that wasn't it
Review feedback on #312: "a second install pinned to a different nightly leaves the stub unchanged" reran install() under the SAME fixed __TASKLESS_CLI__ define twice, so it was an idempotent-reinstall check, not a cross-pin one — a real different pin can't be produced from a single compile-time Vite define within one test run. Renamed that test to describe what it actually checks, and added the real cross-pin case: hand-craft a stub via buildSkillStub() with an older, differently-pinned description (as a pre-fix source file would have produced), write it to disk, then run this build's install() and assert it converges onto the current, invocation-free description rather than leaving the earlier nightly's frozen copy in place. Mutation-checked by reintroducing the stale invocation into skills/taskless/SKILL.md's description: both this new test and the existing "names no CLI package" test failed as expected. Reverted; both pass again.
1 parent 97cd2f7 commit e593f2a

1 file changed

Lines changed: 45 additions & 3 deletions

File tree

‎packages/cli/test/nightly/stub-description-invocation.test.ts‎

Lines changed: 45 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import { mkdir, mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
22
import { tmpdir } from "node:os";
3-
import { join } from "node:path";
3+
import { dirname, join } from "node:path";
44
import { afterEach, beforeEach, describe, expect, it } from "vitest";
55

6+
import { buildSkillStub } from "../../src/install/canonical";
67
import { parseFrontmatter } from "../../src/install/frontmatter";
78
import {
89
applyInstallPlan,
@@ -98,13 +99,54 @@ describe("installing a nightly writes a stub description that names no CLI packa
9899
expect(canonical).not.toContain("npx @taskless/cli agent");
99100
});
100101

101-
it("a second install pinned to a different nightly leaves the stub unchanged", async () => {
102+
it("a second install under the SAME pin is idempotent: nothing gets rewritten", async () => {
102103
await install();
103104
const first = await readFile(skillStubPath(), "utf8");
104105

105106
// Re-running install (same build, so same pin) must not rewrite a stub
106-
// whose description never carried a version to begin with.
107+
// whose description never carried a version to begin with. The genuine
108+
// cross-pin case — an EARLIER, differently pinned install's stub — is
109+
// covered separately below, since a single compile-time define can't
110+
// produce two different pins within one test run.
107111
await install();
108112
expect(await readFile(skillStubPath(), "utf8")).toBe(first);
109113
});
114+
115+
it("a stub frozen by an EARLIER, differently pinned nightly converges on the next install", async () => {
116+
// Simulates the actual defect in taskless/cli#298: a project installed an
117+
// older nightly, pinned to a DIFFERENT version, back when a skill's
118+
// `description` still carried a baked-in CLI invocation. That earlier
119+
// install's stub is not reachable by calling `install()` twice under this
120+
// file's single fixed `__TASKLESS_CLI__` define (a compile-time Vite
121+
// define can't vary within one test run), so it is hand-crafted here with
122+
// `buildSkillStub` instead — the same builder `writeSkill` itself calls,
123+
// fed the OLD-style description a pre-fix source file would have produced.
124+
await mkdir(dirname(skillStubPath()), { recursive: true });
125+
const frozenByEarlierNightly = buildSkillStub({
126+
name: "taskless",
127+
description:
128+
"Use for any Taskless task. Fetch recipes via " +
129+
"`npx @taskless/cli-nightly@0.0.0-nightly.previous agent route`.",
130+
});
131+
await writeFile(skillStubPath(), frozenByEarlierNightly, "utf8");
132+
133+
await install();
134+
135+
const rewritten = await readFile(skillStubPath(), "utf8");
136+
const rewrittenDescription = parseFrontmatter(rewritten).data
137+
.description as string;
138+
139+
// The stub actually changed — this build's install converged it rather
140+
// than leaving the earlier nightly's frozen copy in place.
141+
expect(rewritten).not.toBe(frozenByEarlierNightly);
142+
// It converged onto the CURRENT source description (invocation-free), not
143+
// merely onto some other pin.
144+
const currentDescription = getEmbeddedSkills().find(
145+
(s) => s.name === "taskless"
146+
)?.description;
147+
expect(rewrittenDescription).toBe(currentDescription);
148+
// And, the property the whole fix establishes: no pinned or unpinned CLI
149+
// package reference survives, from either the old install or this one.
150+
expect(rewrittenDescription).not.toMatch(/@taskless\/cli/);
151+
});
110152
});

0 commit comments

Comments
 (0)