@bastani/atomic 0.5.25 → 0.5.26-0
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,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deterministic impeccable scan — runs the `impeccable detect --json` CLI
|
|
3
|
+
* against a design directory and returns structured findings.
|
|
4
|
+
*
|
|
5
|
+
* No LLM call; the refinement loop surfaces these findings to the
|
|
6
|
+
* apply-changes stage so the agent can fix banned anti-patterns
|
|
7
|
+
* alongside user feedback.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { IMPECCABLE_SCAN_CMD } from "./constants.ts";
|
|
11
|
+
|
|
12
|
+
/** Shape of a single finding emitted by `impeccable detect --json`. */
|
|
13
|
+
export interface ScanFinding {
|
|
14
|
+
readonly antipattern: string;
|
|
15
|
+
readonly name: string;
|
|
16
|
+
readonly description: string;
|
|
17
|
+
readonly file: string;
|
|
18
|
+
readonly line: number;
|
|
19
|
+
readonly snippet: string;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Result of running the scanner. Discriminated on `available` so callers
|
|
24
|
+
* can distinguish "ran successfully, no findings" from "scanner missing".
|
|
25
|
+
*/
|
|
26
|
+
export type ScanResult =
|
|
27
|
+
| { readonly available: true; readonly findings: readonly ScanFinding[] }
|
|
28
|
+
| { readonly available: false; readonly reason: string };
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Run `impeccable detect --json` against `designDir`. The CLI exits 0
|
|
32
|
+
* whether or not findings exist, so we parse the JSON array and return
|
|
33
|
+
* its length. If the CLI is missing or its output is not parseable,
|
|
34
|
+
* return `{ available: false, reason }` so the caller can gracefully
|
|
35
|
+
* proceed without scan input.
|
|
36
|
+
*/
|
|
37
|
+
export async function runImpeccableScan(
|
|
38
|
+
designDir: string,
|
|
39
|
+
): Promise<ScanResult> {
|
|
40
|
+
const [cmd, ...args] = IMPECCABLE_SCAN_CMD;
|
|
41
|
+
const proc = Bun.spawn([cmd, ...args, designDir], {
|
|
42
|
+
stdout: "pipe",
|
|
43
|
+
stderr: "pipe",
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
const [stdout, stderr, exitCode] = await Promise.all([
|
|
47
|
+
new Response(proc.stdout).text(),
|
|
48
|
+
new Response(proc.stderr).text(),
|
|
49
|
+
proc.exited,
|
|
50
|
+
]);
|
|
51
|
+
|
|
52
|
+
if (exitCode !== 0) {
|
|
53
|
+
return {
|
|
54
|
+
available: false,
|
|
55
|
+
reason: `exit ${exitCode}: ${stderr.trim() || stdout.trim() || "no output"}`,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const jsonStart = stdout.indexOf("[");
|
|
60
|
+
const jsonEnd = stdout.lastIndexOf("]");
|
|
61
|
+
if (jsonStart === -1 || jsonEnd === -1 || jsonEnd < jsonStart) {
|
|
62
|
+
return {
|
|
63
|
+
available: false,
|
|
64
|
+
reason: `could not locate JSON array in scanner output`,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
try {
|
|
69
|
+
const parsed: unknown = JSON.parse(stdout.slice(jsonStart, jsonEnd + 1));
|
|
70
|
+
if (!Array.isArray(parsed)) {
|
|
71
|
+
return { available: false, reason: "scanner output was not a JSON array" };
|
|
72
|
+
}
|
|
73
|
+
return { available: true, findings: parsed as ScanFinding[] };
|
|
74
|
+
} catch (err) {
|
|
75
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
76
|
+
return { available: false, reason: `JSON parse failed: ${message}` };
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Returns true iff the scanner ran successfully AND reported at least
|
|
82
|
+
* one finding. Narrows the union so callers can access `findings`.
|
|
83
|
+
*/
|
|
84
|
+
export function hasBlockingFindings(
|
|
85
|
+
scan: ScanResult,
|
|
86
|
+
): scan is { available: true; findings: readonly ScanFinding[] } {
|
|
87
|
+
return scan.available && scan.findings.length > 0;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Render findings as a human-readable block for inclusion in agent
|
|
92
|
+
* prompts. Groups by anti-pattern id, lists each file:line with snippet.
|
|
93
|
+
*/
|
|
94
|
+
export function renderScanFindings(
|
|
95
|
+
findings: readonly ScanFinding[],
|
|
96
|
+
): string {
|
|
97
|
+
if (findings.length === 0) return "";
|
|
98
|
+
|
|
99
|
+
const grouped = new Map<string, ScanFinding[]>();
|
|
100
|
+
for (const f of findings) {
|
|
101
|
+
const bucket = grouped.get(f.antipattern) ?? [];
|
|
102
|
+
bucket.push(f);
|
|
103
|
+
grouped.set(f.antipattern, bucket);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const sections: string[] = [];
|
|
107
|
+
for (const [antipattern, items] of grouped) {
|
|
108
|
+
const header = `### ${items[0]!.name} (${antipattern}) — ${items.length} occurrence(s)`;
|
|
109
|
+
const description = items[0]!.description;
|
|
110
|
+
const locations = items
|
|
111
|
+
.map((f) => ` - ${f.file}:${f.line} — \`${f.snippet}\``)
|
|
112
|
+
.join("\n");
|
|
113
|
+
sections.push(`${header}\n${description}\n${locations}`);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return sections.join("\n\n");
|
|
117
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Validation helpers — refinement loop exit detection and critique parsing.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Signal phrases that indicate the user has approved the design and
|
|
7
|
+
* wants to exit the refinement loop. Checked against the feedback
|
|
8
|
+
* stage's extracted assistant text (which includes AskUserQuestion
|
|
9
|
+
* responses and the agent's reaction).
|
|
10
|
+
*/
|
|
11
|
+
const COMPLETION_SIGNALS = [
|
|
12
|
+
"approve and export",
|
|
13
|
+
"approved",
|
|
14
|
+
"looks good",
|
|
15
|
+
"ship it",
|
|
16
|
+
"done",
|
|
17
|
+
"export",
|
|
18
|
+
"user approved",
|
|
19
|
+
"user selected.*approve",
|
|
20
|
+
"user chose.*approve",
|
|
21
|
+
] as const;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Detect whether the user signaled "done" via AskUserQuestion in the
|
|
25
|
+
* feedback stage. The feedback stage's prompt instructs the agent to
|
|
26
|
+
* include one of the completion signal phrases when the user approves.
|
|
27
|
+
*
|
|
28
|
+
* Returns `true` if the refinement loop should exit.
|
|
29
|
+
*/
|
|
30
|
+
export function isRefinementComplete(feedbackResult: string): boolean {
|
|
31
|
+
const lower = feedbackResult.toLowerCase();
|
|
32
|
+
return COMPLETION_SIGNALS.some((signal) => {
|
|
33
|
+
if (signal.includes(".*")) {
|
|
34
|
+
return new RegExp(signal, "i").test(lower);
|
|
35
|
+
}
|
|
36
|
+
return lower.includes(signal);
|
|
37
|
+
});
|
|
38
|
+
}
|