@bastani/atomic 0.5.25 → 0.5.26
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agents/skills/ado-commit/SKILL.md +92 -0
- package/.agents/skills/ado-create-pr/SKILL.md +209 -0
- package/.claude/settings.json +1 -0
- package/.mcp.json +5 -0
- package/.opencode/opencode.json +7 -1
- package/README.md +150 -116
- package/assets/settings.schema.json +2 -2
- package/dist/sdk/runtime/executor.d.ts.map +1 -1
- package/dist/sdk/workflows/builtin/open-claude-design/claude/index.d.ts +46 -0
- package/dist/sdk/workflows/builtin/open-claude-design/claude/index.d.ts.map +1 -0
- package/dist/sdk/workflows/builtin/open-claude-design/copilot/index.d.ts +34 -0
- package/dist/sdk/workflows/builtin/open-claude-design/copilot/index.d.ts.map +1 -0
- package/dist/sdk/workflows/builtin/open-claude-design/helpers/constants.d.ts +72 -0
- package/dist/sdk/workflows/builtin/open-claude-design/helpers/constants.d.ts.map +1 -0
- package/dist/sdk/workflows/builtin/open-claude-design/helpers/design-system.d.ts +46 -0
- package/dist/sdk/workflows/builtin/open-claude-design/helpers/design-system.d.ts.map +1 -0
- package/dist/sdk/workflows/builtin/open-claude-design/helpers/export.d.ts +32 -0
- package/dist/sdk/workflows/builtin/open-claude-design/helpers/export.d.ts.map +1 -0
- package/dist/sdk/workflows/builtin/open-claude-design/helpers/import.d.ts +33 -0
- package/dist/sdk/workflows/builtin/open-claude-design/helpers/import.d.ts.map +1 -0
- package/dist/sdk/workflows/builtin/open-claude-design/helpers/prompts.d.ts +106 -0
- package/dist/sdk/workflows/builtin/open-claude-design/helpers/prompts.d.ts.map +1 -0
- package/dist/sdk/workflows/builtin/open-claude-design/helpers/scan.d.ts +50 -0
- package/dist/sdk/workflows/builtin/open-claude-design/helpers/scan.d.ts.map +1 -0
- package/dist/sdk/workflows/builtin/open-claude-design/helpers/validation.d.ts +12 -0
- package/dist/sdk/workflows/builtin/open-claude-design/helpers/validation.d.ts.map +1 -0
- package/dist/sdk/workflows/builtin/open-claude-design/opencode/index.d.ts +36 -0
- package/dist/sdk/workflows/builtin/open-claude-design/opencode/index.d.ts.map +1 -0
- package/dist/services/config/atomic-config.d.ts +6 -0
- package/dist/services/config/atomic-config.d.ts.map +1 -1
- package/dist/services/config/scm-sync.d.ts +37 -0
- package/dist/services/config/scm-sync.d.ts.map +1 -0
- package/package.json +7 -7
- package/src/cli.ts +2 -2
- package/src/commands/cli/chat/index.ts +8 -1
- package/src/commands/cli/config.ts +34 -10
- package/src/commands/cli/init/index.ts +9 -0
- package/src/sdk/runtime/executor.ts +13 -0
- package/src/sdk/workflows/builtin/open-claude-design/claude/index.ts +499 -0
- package/src/sdk/workflows/builtin/open-claude-design/copilot/index.ts +507 -0
- package/src/sdk/workflows/builtin/open-claude-design/helpers/constants.ts +159 -0
- package/src/sdk/workflows/builtin/open-claude-design/helpers/design-system.ts +88 -0
- package/src/sdk/workflows/builtin/open-claude-design/helpers/export.ts +193 -0
- package/src/sdk/workflows/builtin/open-claude-design/helpers/import.ts +52 -0
- package/src/sdk/workflows/builtin/open-claude-design/helpers/prompts.ts +1110 -0
- package/src/sdk/workflows/builtin/open-claude-design/helpers/scan.ts +117 -0
- package/src/sdk/workflows/builtin/open-claude-design/helpers/validation.ts +38 -0
- package/src/sdk/workflows/builtin/open-claude-design/opencode/index.ts +570 -0
- package/src/services/config/atomic-config.ts +12 -0
- package/src/services/config/scm-sync.ts +174 -0
- package/src/services/config/settings.ts +19 -0
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Source-control-driven MCP server enable/disable sync.
|
|
3
|
+
*
|
|
4
|
+
* When the user sets `scm` in `.atomic/settings.json` to one of
|
|
5
|
+
* `github`, `azure-devops`, or `sapling`, Atomic keeps the corresponding
|
|
6
|
+
* MCP servers in the project's agent configs consistent on every
|
|
7
|
+
* `atomic chat` / `atomic workflow` startup:
|
|
8
|
+
*
|
|
9
|
+
* - `.claude/settings.json` → updates the `disabledMcpjsonServers` array
|
|
10
|
+
* - `.opencode/opencode.json` → flips `mcp.<server>.enabled` flags
|
|
11
|
+
*
|
|
12
|
+
* Only servers that already exist in the config are touched — we never
|
|
13
|
+
* add MCP server definitions the user didn't set up. Files that don't
|
|
14
|
+
* exist are skipped (the user may not use that agent).
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import { join } from "node:path";
|
|
18
|
+
import { pathExists } from "../system/copy.ts";
|
|
19
|
+
import type { ScmProvider } from "./atomic-config.ts";
|
|
20
|
+
import { readAtomicConfig } from "./atomic-config.ts";
|
|
21
|
+
|
|
22
|
+
const SCM_MCP_SERVERS = ["github", "azure-devops"] as const;
|
|
23
|
+
type ScmMcpServer = (typeof SCM_MCP_SERVERS)[number];
|
|
24
|
+
|
|
25
|
+
/** Which SCM MCP servers should be enabled for each scm value. */
|
|
26
|
+
function enabledServersFor(scm: ScmProvider): Set<ScmMcpServer> {
|
|
27
|
+
if (scm === "github") return new Set(["github"]);
|
|
28
|
+
if (scm === "azure-devops") return new Set(["azure-devops"]);
|
|
29
|
+
return new Set();
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Pure helper: returns the `--disable-mcp-server <name>` flag sequence to
|
|
34
|
+
* append when spawning Copilot CLI, given a selected scm provider.
|
|
35
|
+
*
|
|
36
|
+
* Copilot has no on-disk MCP server enable/disable store, so Atomic
|
|
37
|
+
* injects the flags on the CLI invocation instead. Returns an empty
|
|
38
|
+
* array when scm is unset so callers can spread unconditionally.
|
|
39
|
+
*/
|
|
40
|
+
export function copilotScmDisableFlags(scm: ScmProvider | undefined): string[] {
|
|
41
|
+
if (!scm) return [];
|
|
42
|
+
const enabled = enabledServersFor(scm);
|
|
43
|
+
const flags: string[] = [];
|
|
44
|
+
for (const name of SCM_MCP_SERVERS) {
|
|
45
|
+
if (!enabled.has(name)) flags.push("--disable-mcp-server", name);
|
|
46
|
+
}
|
|
47
|
+
return flags;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Resolve Copilot's scm-derived `--disable-mcp-server` flags from the
|
|
52
|
+
* project's atomic config. Best-effort — returns `[]` on any failure.
|
|
53
|
+
*/
|
|
54
|
+
export async function getCopilotScmDisableFlags(
|
|
55
|
+
projectRoot: string,
|
|
56
|
+
): Promise<string[]> {
|
|
57
|
+
try {
|
|
58
|
+
const config = await readAtomicConfig(projectRoot);
|
|
59
|
+
return copilotScmDisableFlags(config?.scm);
|
|
60
|
+
} catch {
|
|
61
|
+
return [];
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
async function readJson(path: string): Promise<Record<string, unknown> | null> {
|
|
66
|
+
try {
|
|
67
|
+
const parsed: unknown = await Bun.file(path).json();
|
|
68
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
69
|
+
return parsed as Record<string, unknown>;
|
|
70
|
+
}
|
|
71
|
+
} catch {
|
|
72
|
+
// Missing or invalid JSON — treat as absent.
|
|
73
|
+
}
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
async function writeJson(path: string, data: Record<string, unknown>): Promise<void> {
|
|
78
|
+
await Bun.write(path, JSON.stringify(data, null, 2) + "\n");
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Update `disabledMcpjsonServers` in Claude's settings so that servers
|
|
83
|
+
* for the non-selected providers are disabled. Preserves any other
|
|
84
|
+
* entries the user has added to the array.
|
|
85
|
+
*/
|
|
86
|
+
async function syncClaudeSettings(
|
|
87
|
+
projectRoot: string,
|
|
88
|
+
enabled: Set<ScmMcpServer>,
|
|
89
|
+
): Promise<void> {
|
|
90
|
+
const path = join(projectRoot, ".claude", "settings.json");
|
|
91
|
+
if (!(await pathExists(path))) return;
|
|
92
|
+
|
|
93
|
+
const settings = await readJson(path);
|
|
94
|
+
if (!settings) return;
|
|
95
|
+
|
|
96
|
+
const rawDisabled = settings.disabledMcpjsonServers;
|
|
97
|
+
const existing: string[] = Array.isArray(rawDisabled)
|
|
98
|
+
? rawDisabled.filter((v): v is string => typeof v === "string")
|
|
99
|
+
: [];
|
|
100
|
+
|
|
101
|
+
// Drop any SCM MCP server entry, then add back the ones that should be disabled.
|
|
102
|
+
const withoutScm = existing.filter(
|
|
103
|
+
(name): name is string => !(SCM_MCP_SERVERS as readonly string[]).includes(name),
|
|
104
|
+
);
|
|
105
|
+
const toDisable = SCM_MCP_SERVERS.filter((name) => !enabled.has(name));
|
|
106
|
+
const next = [...withoutScm, ...toDisable];
|
|
107
|
+
|
|
108
|
+
if (arraysEqual(existing, next)) return;
|
|
109
|
+
|
|
110
|
+
settings.disabledMcpjsonServers = next;
|
|
111
|
+
await writeJson(path, settings);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Flip `enabled` on the GitHub / Azure DevOps MCP server entries in
|
|
116
|
+
* OpenCode's config. Only touches servers the user already has — we
|
|
117
|
+
* don't invent server definitions.
|
|
118
|
+
*/
|
|
119
|
+
async function syncOpencodeSettings(
|
|
120
|
+
projectRoot: string,
|
|
121
|
+
enabled: Set<ScmMcpServer>,
|
|
122
|
+
): Promise<void> {
|
|
123
|
+
const path = join(projectRoot, ".opencode", "opencode.json");
|
|
124
|
+
if (!(await pathExists(path))) return;
|
|
125
|
+
|
|
126
|
+
const config = await readJson(path);
|
|
127
|
+
if (!config) return;
|
|
128
|
+
|
|
129
|
+
const mcp = config.mcp;
|
|
130
|
+
if (!mcp || typeof mcp !== "object" || Array.isArray(mcp)) return;
|
|
131
|
+
const servers = mcp as Record<string, unknown>;
|
|
132
|
+
|
|
133
|
+
let changed = false;
|
|
134
|
+
for (const name of SCM_MCP_SERVERS) {
|
|
135
|
+
const server = servers[name];
|
|
136
|
+
if (!server || typeof server !== "object" || Array.isArray(server)) continue;
|
|
137
|
+
const serverObj = server as Record<string, unknown>;
|
|
138
|
+
const shouldEnable = enabled.has(name);
|
|
139
|
+
if (serverObj.enabled !== shouldEnable) {
|
|
140
|
+
serverObj.enabled = shouldEnable;
|
|
141
|
+
changed = true;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
if (!changed) return;
|
|
146
|
+
await writeJson(path, config);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function arraysEqual(a: string[], b: string[]): boolean {
|
|
150
|
+
if (a.length !== b.length) return false;
|
|
151
|
+
for (let i = 0; i < a.length; i++) if (a[i] !== b[i]) return false;
|
|
152
|
+
return true;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Apply the current `scm` selection to the project's agent config files.
|
|
157
|
+
* No-op when `scm` is unset. Swallows errors so a malformed agent
|
|
158
|
+
* config never blocks `atomic chat` / `atomic workflow` startup.
|
|
159
|
+
*/
|
|
160
|
+
export async function syncScmMcpServers(projectRoot: string): Promise<void> {
|
|
161
|
+
try {
|
|
162
|
+
const config = await readAtomicConfig(projectRoot);
|
|
163
|
+
const scm = config?.scm;
|
|
164
|
+
if (!scm) return;
|
|
165
|
+
|
|
166
|
+
const enabled = enabledServersFor(scm);
|
|
167
|
+
await Promise.all([
|
|
168
|
+
syncClaudeSettings(projectRoot, enabled),
|
|
169
|
+
syncOpencodeSettings(projectRoot, enabled),
|
|
170
|
+
]);
|
|
171
|
+
} catch {
|
|
172
|
+
// Best-effort: never block startup on a config write failure.
|
|
173
|
+
}
|
|
174
|
+
}
|
|
@@ -15,12 +15,14 @@ import { SETTINGS_SCHEMA_URL } from "./settings-schema.ts";
|
|
|
15
15
|
import { ensureDir } from "../system/copy.ts";
|
|
16
16
|
import { errorMessage } from "../../sdk/errors.ts";
|
|
17
17
|
import type { AgentKey, ProviderOverrides } from "./definitions.ts";
|
|
18
|
+
import type { ScmProvider } from "./atomic-config.ts";
|
|
18
19
|
|
|
19
20
|
interface AtomicSettings {
|
|
20
21
|
$schema?: string;
|
|
21
22
|
version?: number;
|
|
22
23
|
lastUpdated?: string;
|
|
23
24
|
telemetryEnabled?: boolean;
|
|
25
|
+
scm?: ScmProvider;
|
|
24
26
|
providers?: Partial<Record<AgentKey, ProviderOverrides>>;
|
|
25
27
|
}
|
|
26
28
|
|
|
@@ -64,3 +66,20 @@ export async function setTelemetryEnabled(enabled: boolean): Promise<void> {
|
|
|
64
66
|
console.warn(`[settings] failed to set telemetry: ${errorMessage(e)}`);
|
|
65
67
|
}
|
|
66
68
|
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Set the selected source control provider in global settings.
|
|
72
|
+
*
|
|
73
|
+
* The value is read on every `atomic chat` / `atomic workflow` startup
|
|
74
|
+
* to reconcile the enable/disable state of the GitHub and Azure DevOps
|
|
75
|
+
* MCP servers in `.claude/settings.json` and `.opencode/opencode.json`.
|
|
76
|
+
*/
|
|
77
|
+
export async function setScmProvider(scm: ScmProvider): Promise<void> {
|
|
78
|
+
try {
|
|
79
|
+
const settings = await loadSettingsFile(globalSettingsPath());
|
|
80
|
+
settings.scm = scm;
|
|
81
|
+
await writeGlobalSettings(settings);
|
|
82
|
+
} catch (e) {
|
|
83
|
+
console.warn(`[settings] failed to set scm: ${errorMessage(e)}`);
|
|
84
|
+
}
|
|
85
|
+
}
|