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
2 changes: 1 addition & 1 deletion .mcp.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"github": {
"type": "http",
"url": "https://api.githubcopilot.com/mcp",
"headers": { "Authorization": "Bearer YOUR_GITHUB_PAT" }
"headers": { "Authorization": "Bearer ${GITHUB_PERSONAL_ACCESS_TOKEN}" }
}
}
}
4 changes: 3 additions & 1 deletion .opencode/opencode.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
"github": {
"type": "remote",
"url": "https://api.githubcopilot.com/mcp",
"headers": { "Authorization": "Bearer YOUR_GITHUB_PAT" }
"headers": {
"Authorization": "Bearer ${env:GITHUB_PERSONAL_ACCESS_TOKEN}"
}
}
}
}
94 changes: 7 additions & 87 deletions src/commands/cli/init/index.ts
Original file line number Diff line number Diff line change
@@ -1,106 +1,26 @@
/**
* Automatic project setup — replaces the interactive `atomic init` command.
*
* Detects the repo's SCM, applies onboarding files (MCP configs, settings),
* registers the workspace as trusted, and installs SCM-specific skills.
*
* Called transparently during `atomic chat` preflight so users never need
* to think about initialization.
* Applies onboarding files (MCP configs, settings) and registers the
* workspace as trusted. Called transparently during `atomic chat` preflight
* so users never need to think about initialization.
*/

import { join, resolve } from "node:path";
import {
AGENT_CONFIG,
type AgentKey,
type SourceControlType,
SCM_SKILLS_BY_TYPE,
detectScmType,
} from "../../../services/config/index.ts";
import { pathExists } from "../../../services/system/copy.ts";
import { resolve } from "node:path";
import type { AgentKey } from "../../../services/config/index.ts";
import { getConfigRoot } from "../../../services/config/config-path.ts";
import { upsertTrustedWorkspacePath } from "../../../services/config/settings.ts";
import { applyManagedOnboardingFiles } from "./onboarding.ts";
import { installLocalScmSkills, syncProjectScmSkills } from "./scm.ts";

/**
* Check whether all expected SCM skills are already present on disk.
*/
async function areScmSkillsInstalled(
agentKey: AgentKey,
projectRoot: string,
scmType: SourceControlType,
): Promise<boolean> {
const skillNames = SCM_SKILLS_BY_TYPE[scmType];
const skillsDir = join(projectRoot, AGENT_CONFIG[agentKey].folder, "skills");

for (const name of skillNames) {
if (!(await pathExists(join(skillsDir, name)))) {
return false;
}
}
return true;
}

function isInstalledPackage(): boolean {
return import.meta.dir.includes("node_modules");
}

/**
* Ensure the project is configured for the given agent.
*
* Idempotent — safe to call on every `atomic chat` invocation. Expensive
* operations (skill installation via `bunx skills add`) are skipped when
* the skills are already present on disk. Onboarding file merges are
* always applied since they are cheap and self-healing.
*
* Errors in skill installation are swallowed so the agent can still launch.
* Ensure the project is configured for the given agent. Idempotent — safe
* to call on every `atomic chat` invocation.
*/
export async function ensureProjectSetup(
agentKey: AgentKey,
projectRoot: string,
): Promise<void> {
const configRoot = getConfigRoot();
const detectedScm = await detectScmType(projectRoot);

// Apply onboarding files (idempotent merge, SCM-gated entries handled internally)
await applyManagedOnboardingFiles(agentKey, projectRoot, configRoot);

// Register trusted workspace
await upsertTrustedWorkspacePath(resolve(projectRoot), agentKey);

// Install SCM skills if detected and not yet present (best-effort)
if (detectedScm) {
try {
const alreadyInstalled = await areScmSkillsInstalled(
agentKey,
projectRoot,
detectedScm,
);
if (!alreadyInstalled) {
if (isInstalledPackage()) {
// npm/bunx install: fetch via the skills CLI
await installLocalScmSkills({
scmType: detectedScm,
agentKey,
cwd: projectRoot,
});
} else {
// Source checkout (e.g. `bun run dev`): copy from the canonical
// `.agents/skills` directory so prompt edits in-repo flow through
// to the target project without needing a publish or git push.
await syncProjectScmSkills({
scmType: detectedScm,
sourceSkillsDir: join(configRoot, ".agents", "skills"),
targetSkillsDir: join(
projectRoot,
AGENT_CONFIG[agentKey].folder,
"skills",
),
});
}
}
} catch {
// Skills installation is best-effort — don't block the agent launch
}
}
}
175 changes: 0 additions & 175 deletions src/commands/cli/init/scm.ts

This file was deleted.

11 changes: 3 additions & 8 deletions src/completions/bash.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ _atomic_completions() {

local commands="init chat workflow session config completions"
local agents="claude opencode copilot"
local scms="github sapling"
local global_opts="-y --yes --no-banner -v --version -h --help"

# Walk the words to find the command chain (skip flags and their values)
Expand All @@ -19,8 +18,8 @@ _atomic_completions() {
while [[ $i -lt $cword ]]; do
local w="\${words[$i]}"
case "$w" in
-a|--agent|-s|--scm|-n|--name) (( i++ )) ;; # skip flag value
-*) ;; # skip other flags
-a|--agent|-n|--name) (( i++ )) ;; # skip flag value
-*) ;; # skip other flags
*)
if [[ -z "$cmd1" ]]; then cmd1="$w"
elif [[ -z "$cmd2" ]]; then cmd2="$w"
Expand All @@ -37,10 +36,6 @@ _atomic_completions() {
COMPREPLY=( $(compgen -W "$agents" -- "$cur") )
return
;;
-s|--scm)
COMPREPLY=( $(compgen -W "$scms" -- "$cur") )
return
;;
esac

# Top-level (no subcommand yet)
Expand All @@ -51,7 +46,7 @@ _atomic_completions() {

case "$cmd1" in
init)
COMPREPLY=( $(compgen -W "-a --agent -s --scm -h --help" -- "$cur") )
COMPREPLY=( $(compgen -W "-a --agent -h --help" -- "$cur") )
;;
chat)
if [[ -z "$cmd2" ]]; then
Expand Down
4 changes: 1 addition & 3 deletions src/completions/fish.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ complete -c atomic -f
# ── Helpers ─────────────────────────────────────────────────────────────────

set -l agents claude opencode copilot
set -l scms github sapling

# Condition helpers — true when the command line matches a specific depth.
# "__fish_seen_subcommand_from X" is true once token X has appeared.
Expand All @@ -36,7 +35,7 @@ function __atomic_using_cmd
set idx (math $idx + 1)
# Skip flag value for known value-flags
switch $tokens[(math $idx - 1)]
case -a --agent -s --scm -n --name
case -a --agent -n --name
set idx (math $idx + 1)
end
case '*'
Expand Down Expand Up @@ -78,7 +77,6 @@ complete -c atomic -n __atomic_no_subcommand -a completions -d 'Output shell com
# ── init ────────────────────────────────────────────────────────────────────

complete -c atomic -n '__atomic_using_cmd init' -s a -l agent -d 'Agent to configure' -r -a "$agents"
complete -c atomic -n '__atomic_using_cmd init' -s s -l scm -d 'Source control system' -r -a "$scms"

# ── chat ────────────────────────────────────────────────────────────────────

Expand Down
Loading
Loading