feat(cli): Multi-tool detection for init#16
Conversation
…ics spec Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Separate detection signals from install directory in ToolDescriptor to support file-based detection (e.g., CLAUDE.md) in addition to directories. No behavior change — Claude Code still detected by .claude/ directory only. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add OpenCode (.opencode/, opencode.jsonc, opencode.json) and Cursor (.cursor/, .cursorrules) tool detection. Expand Claude Code detection to also trigger on CLAUDE.md file. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Instead of showing "no supported tool directories" message, install skills to .agents/skills/ as a fallback when no AI tools are detected. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
List all supported tools and their detection signals. Add staleness test for multiple detected tools. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Delete unused stringifyFrontmatter and formatJson functions. De-export 9 types/schemas that are only used within their own modules. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…t spec Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Expands taskless init to detect multiple AI coding tools (Claude Code, OpenCode, Cursor) via file/directory signals and install skills for each detected tool, with a .agents/skills/ fallback when nothing is detected. It also removes dead/unused code and updates specs/docs to reflect the new behavior.
Changes:
- Refactor tool detection to use per-tool detection signals (
detect[]) separate from install root (installDir), plus add OpenCode/Cursor and a.agentsfallback target. - Update
initcommand output + help/specs, and add install/detection/staleness tests. - Clean up unused helpers/types (incl. removing
capabilities.ts,stringifyFrontmatter,formatJson, and de-exporting several internal-only types).
Reviewed changes
Copilot reviewed 23 out of 28 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/cli/test/install.test.ts | New unit tests for multi-tool detection, install paths, fallback behavior, and staleness reporting. |
| packages/cli/test/cli.test.ts | Updates CLI integration test expectations for .agents fallback output. |
| packages/cli/test/capabilities.test.ts | Removes tests for deleted isValidSpecVersion. |
| packages/cli/src/util/format.ts | Removes unused formatJson output helper. |
| packages/cli/src/telemetry.ts | De-exports TelemetryClient interface (now internal). |
| packages/cli/src/schemas/check.ts | Makes checkResultSchema internal; keeps exported output/error schemas. |
| packages/cli/src/rules/verify.ts | De-exports VerifyResult interface (now internal). |
| packages/cli/src/rules/scan.ts | De-exports ScanResult interface (now internal). |
| packages/cli/src/install/install.ts | Adds detection signals + OpenCode/Cursor + .agents fallback descriptor; updates install/staleness to use installDir. |
| packages/cli/src/install/frontmatter.ts | Removes unused stringifyFrontmatter helper. |
| packages/cli/src/help/init.txt | Updates help text for multi-tool detection + fallback behavior. |
| packages/cli/src/commands/init.ts | Implements .agents fallback install when no tools detected; updates output paths to installDir. |
| packages/cli/src/capabilities.ts | Deletes unused isValidSpecVersion. |
| packages/cli/src/auth/identity.ts | De-exports Identity interface (now internal). |
| packages/cli/src/auth/device-flow.ts | De-exports device flow types (now internal). |
| openspec/specs/cli-init/spec.md | Updates init spec to cover detection signals, multi-tool support, and fallback install behavior. |
| openspec/specs/analytics/spec.md | Adds analytics spec (PostHog telemetry requirements). |
| openspec/changes/archive/2026-04-07-multi-tool-detection/tasks.md | Archived tasks for multi-tool detection change. |
| openspec/changes/archive/2026-04-07-multi-tool-detection/specs/cli-init/spec.md | Archived spec delta for multi-tool detection. |
| openspec/changes/archive/2026-04-07-multi-tool-detection/proposal.md | Archived proposal for multi-tool detection. |
| openspec/changes/archive/2026-04-07-multi-tool-detection/design.md | Archived design notes for multi-tool detection. |
| openspec/changes/archive/2026-04-07-multi-tool-detection/.openspec.yaml | Archived OpenSpec metadata for multi-tool detection. |
| openspec/changes/archive/2026-04-07-cli-posthog-analytics/tasks.md | Archived tasks for CLI PostHog analytics. |
| openspec/changes/archive/2026-04-07-cli-posthog-analytics/specs/analytics/spec.md | Archived analytics spec. |
| openspec/changes/archive/2026-04-07-cli-posthog-analytics/proposal.md | Archived proposal for CLI analytics. |
| openspec/changes/archive/2026-04-07-cli-posthog-analytics/design.md | Archived design notes for CLI analytics. |
| openspec/changes/archive/2026-04-07-cli-posthog-analytics/.openspec.yaml | Archived OpenSpec metadata for CLI analytics. |
| .changeset/multi-tool-detection.md | Changeset entry for patch release documenting multi-tool detection + fallback. |
Comments suppressed due to low confidence (1)
packages/cli/src/auth/identity.ts:10
Identityis now a private interface, butresolveIdentity()is exported and returnsPromise<Identity>. Withdeclaration: true, this can cause TypeScript “private name” errors for exported APIs. Consider exporting theIdentitytype (or inlining the return type) so the public signature doesn’t reference a private symbol.
interface Identity {
token: string;
orgId: number;
repositoryUrl: string;
}
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…detection Export interfaces/types referenced by exported functions to ensure declaration-safe public API surfaces. Use stat().isFile() instead of access() for file detection signals to avoid false positives on directories. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 20 out of 25 changed files in this pull request and generated 2 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Sync spec with implementation: file detection uses stat().isFile() instead of access(). Clarify config file wording to distinguish presence-only checks from content parsing. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 20 out of 25 changed files in this pull request and generated 5 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
openspec/changes/archive/2026-04-07-multi-tool-detection/design.md
Outdated
Show resolved
Hide resolved
openspec/changes/archive/2026-04-07-multi-tool-detection/tasks.md
Outdated
Show resolved
Hide resolved
openspec/changes/archive/2026-04-07-multi-tool-detection/specs/cli-init/spec.md
Outdated
Show resolved
Hide resolved
… detection Export InstallResult used in installForTool signature. Update archived spec, design doc, and tasks to reflect stat().isFile() for file detection instead of access(). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 20 out of 25 changed files in this pull request and generated 4 comments.
Comments suppressed due to low confidence (1)
packages/cli/src/auth/identity.ts:10
Identitywas made non-exported, but this module still exportsresolveIdentity(...): Promise<Identity>. Withdeclaration: true, TypeScript will error on exported signatures that reference non-exported named types. Either exportIdentity, or changeresolveIdentityto return an inline/structural type so the exported API doesn’t depend on a private symbol.
interface Identity {
token: string;
orgId: number;
repositoryUrl: string;
}
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…atures Comprehensive sweep: export every interface/type that is reachable from an exported function or value signature. Prevents declaration: true issues and stops the incremental Copilot feedback loop. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Document that types transitively referenced by exported functions must stay exported, even when knip flags them as unused. Prevents repeated review cycles from declaration: true issues. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 20 out of 25 changed files in this pull request and generated 1 comment.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…exists When .agents/ exists from a previous fallback install, include it in staleness checks so taskless info reports its status. This makes the fallback location a proper first-class install target for status reporting. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 20 out of 25 changed files in this pull request and generated 1 comment.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Add support for detecting and installing skills into multiple AI coding tools,
not just Claude Code. The CLI now detects OpenCode, Cursor, and an expanded
set of Claude Code signals during
taskless init.When no tools are detected at all, skills are installed to
.agents/skills/as a universal fallback location rather than showing an error message. This
ensures
taskless initalways succeeds regardless of which (or no) AI toolthe user has configured.
Detection signals:
.claude/directory,CLAUDE.mdfile (new).opencode/directory,opencode.jsonc,opencode.json.cursor/directory,.cursorrules.agents/skills/(when nothing else detected)Also cleans up dead code found via knip: removes unused
isValidSpecVersion,stringifyFrontmatter,formatJson, and de-exports 9 internal-only types.