feat(cli): Add dev/self build targets for local CLI dogfooding#41
Merged
Conversation
Bake a build-target-specific invocation into emitted skill/command/recipe content via a Vite define: prod ships `npx @taskless/cli`, `build:dev` an absolute path (validate from another repo), `build:self` a repo-relative path (dogfood in place). dev/self also prepend a one-time banner telling the agent to rebuild if the local CLI is missing. Replace the raw `link-skills` symlink step with a real self-install so local `.claude` matches any other install (stubs delegating to `.taskless`). Harden the installer to never write through a symlinked target directory — a prior link-skills relic could otherwise route stub writes back into source and clobber it. Add a regression test and gitignore the generated self-install artifacts. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Contributor
There was a problem hiding this comment.
Pull request overview
This PR adds non-production build targets for the Taskless CLI so locally built artifacts can be dogfooded (in-repo) or validated (from another repo) without publishing, while making local dogfooding follow the same “real install” path as an actual CLI install.
Changes:
- Introduces
TASKLESS_BUILD_TARGET-driven Vitedefines to bake a build-target-specific CLI invocation string (and optional notice banner) into emitted canonical skill/command content. - Replaces the previous
.claudesymlink-based local workflow by makingpnpm build:selfbuild the CLI and runtaskless init --no-interactiveto install real reference stubs. - Hardens the installer against symlinked target directories (prevents writing stubs through a directory symlink) and adds a regression test for the skill-directory case.
Reviewed changes
Copilot reviewed 13 out of 15 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| turbo.json | Adds TASKLESS_BUILD_TARGET to the build task env inputs for correct caching. |
| scripts/link-skills.ts | Removes the old symlink-based local dogfooding script. |
| README.md | Documents the new local build targets and the self-install workflow. |
| packages/cli/vite.config.ts | Defines build-target-specific invocation + optional notice banner via Vite define. |
| packages/cli/test/apply-install-plan.test.ts | Adds regression coverage for “symlinked skill directory should not be clobbered”. |
| packages/cli/src/util/invocation.ts | Implements invocation rewriting and build-notice insertion helpers. |
| packages/cli/src/install/install.ts | Hardens stub writing by normalizing symlinked target directories before writing. |
| packages/cli/src/install/canonical.ts | Applies invocation rewriting + notice insertion when writing canonical content. |
| packages/cli/src/globals.d.ts | Declares new Vite-injected globals. |
| packages/cli/src/commands/help.ts | Rewrites baked CLI invocation inside rendered help recipes. |
| packages/cli/package.json | Adds build:dev / build:self scripts for the CLI package. |
| package.json | Updates root build scripts; adds build:dev and build:self orchestration. |
| .gitignore | Ignores generated self-install artifacts (canonical skills/commands + stubs). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Update the writeCanonicalSkill/writeCanonicalCommand JSDoc: content is no longer strictly verbatim — dev/self builds rewrite the CLI invocation and prepend a build notice, while prod stays byte-identical. Add a regression test for a symlinked command-namespace directory (.claude/commands/tskl), mirroring the skill-directory case, so the command-path symlink hardening can't regress. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Add two non-production build targets so a locally built CLI can be exercised without publishing, and make local dogfooding behave exactly like a real install.
What
define(TASKLESS_BUILD_TARGET): the CLI invocation baked into emitted skill/command/recipe content is now build-target-specific.pnpm build(prod, default) →npx @taskless/cli— byte-identical to today (no-op).pnpm build:dev→ an absolute path, for validating this build from another repo.pnpm build:self→ a repo-root-relative path, for dogfooding in this repo.dev/selfalso prepend a one-time banner to canonical skill/command bodies telling the agent to rebuild (pnpm build:self) if the local CLI is missing.build:selfnow compiles and runstaskless init --no-interactive, so.claudegets real reference stubs that delegate to the canonical.taskless/store — identical to any other install. The oldscripts/link-skills.ts(which raw-symlinkedskills/into.claude/) is removed.unlinkIfSymlinkguarded only the leaf file, so a leftoverlink-skillsdirectory symlink (.claude/skills/taskless -> ../../skills/taskless) routed stub writes back into source and clobbered it. Removed the two relic committed symlinks and gitignored the generated self-install artifacts.Why
We hit this validating earlier work: there was no way to run the locally built CLI against another checkout, and dogfooding relied on raw symlinks that diverged from a real install. Routing local setup through the install pipeline makes it consistent and reliable — and surfaced the symlink-clobber bug, which is now fixed and covered by a test.
Review notes
applyCliInvocationis a strict no-op when the define equalsnpx @taskless/cli(verified: prod rebuild is a FULL TURBO cache hit, 297 tests pass).dev/selfinvocations bake local paths and must never be published — onlypnpm build/pnpm packageproduce a release artifact.apply-install-plan.test.ts› "does not write through a symlinked skill directory".