@bastani/atomic 0.9.0-alpha.3 → 0.9.0-alpha.4
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/CHANGELOG.md +15 -0
- package/dist/builtin/cursor/package.json +2 -2
- package/dist/builtin/intercom/package.json +1 -1
- package/dist/builtin/mcp/package.json +1 -1
- package/dist/builtin/subagents/package.json +1 -1
- package/dist/builtin/web-access/package.json +1 -1
- package/dist/builtin/workflows/CHANGELOG.md +17 -0
- package/dist/builtin/workflows/README.md +12 -12
- package/dist/builtin/workflows/builtin/goal-prompts.ts +8 -0
- package/dist/builtin/workflows/builtin/goal-runner.ts +96 -1
- package/dist/builtin/workflows/builtin/goal-types.ts +2 -0
- package/dist/builtin/workflows/builtin/goal.d.ts +3 -0
- package/dist/builtin/workflows/builtin/goal.ts +12 -1
- package/dist/builtin/workflows/builtin/index.d.ts +8 -8
- package/dist/builtin/workflows/builtin/open-claude-design-feedback.ts +359 -0
- package/dist/builtin/workflows/builtin/open-claude-design-phases.ts +254 -352
- package/dist/builtin/workflows/builtin/open-claude-design-runner.ts +256 -414
- package/dist/builtin/workflows/builtin/open-claude-design-setup.ts +272 -0
- package/dist/builtin/workflows/builtin/open-claude-design-utils.ts +58 -68
- package/dist/builtin/workflows/builtin/open-claude-design.d.ts +5 -9
- package/dist/builtin/workflows/builtin/open-claude-design.ts +14 -26
- package/dist/builtin/workflows/package.json +1 -1
- package/dist/builtin/workflows/skills/impeccable/SKILL.md +14 -23
- package/dist/builtin/workflows/skills/impeccable/reference/brand.md +2 -2
- package/dist/builtin/workflows/skills/impeccable/reference/live.md +25 -4
- package/dist/builtin/workflows/skills/impeccable/scripts/context-signals.mjs +1 -1
- package/dist/builtin/workflows/skills/impeccable/scripts/context.mjs +724 -29
- package/dist/builtin/workflows/skills/impeccable/scripts/critique-storage.mjs +1 -1
- package/dist/builtin/workflows/skills/impeccable/scripts/detector/browser/injected/index.mjs +219 -7
- package/dist/builtin/workflows/skills/impeccable/scripts/detector/cli/main.mjs +57 -11
- package/dist/builtin/workflows/skills/impeccable/scripts/detector/design-system.mjs +750 -0
- package/dist/builtin/workflows/skills/impeccable/scripts/detector/detect-antipatterns-browser.js +648 -53
- package/dist/builtin/workflows/skills/impeccable/scripts/detector/detect-antipatterns.mjs +7 -0
- package/dist/builtin/workflows/skills/impeccable/scripts/detector/engines/browser/detect-url.mjs +29 -4
- package/dist/builtin/workflows/skills/impeccable/scripts/detector/engines/regex/detect-text.mjs +44 -11
- package/dist/builtin/workflows/skills/impeccable/scripts/detector/engines/static-html/css-cascade.mjs +29 -0
- package/dist/builtin/workflows/skills/impeccable/scripts/detector/engines/static-html/detect-html.mjs +27 -1
- package/dist/builtin/workflows/skills/impeccable/scripts/detector/node/file-system.mjs +1 -1
- package/dist/builtin/workflows/skills/impeccable/scripts/detector/registry/antipatterns.mjs +29 -0
- package/dist/builtin/workflows/skills/impeccable/scripts/detector/rules/checks.mjs +401 -46
- package/dist/builtin/workflows/skills/impeccable/scripts/detector/shared/inline-ignores.mjs +148 -0
- package/dist/builtin/workflows/skills/impeccable/scripts/detector/shared/page.mjs +6 -6
- package/dist/builtin/workflows/skills/impeccable/scripts/{design-parser.mjs → lib/design-parser.mjs} +8 -1
- package/dist/builtin/workflows/skills/impeccable/scripts/lib/impeccable-config.mjs +638 -0
- package/dist/builtin/workflows/skills/impeccable/scripts/lib/impeccable-paths.mjs +128 -0
- package/dist/builtin/workflows/skills/impeccable/scripts/{is-generated.mjs → lib/is-generated.mjs} +2 -2
- package/dist/builtin/workflows/skills/impeccable/scripts/lib/target-args.mjs +42 -0
- package/dist/builtin/workflows/skills/impeccable/scripts/live/browser-script-parts.mjs +49 -0
- package/dist/builtin/workflows/skills/impeccable/scripts/{live-completion.mjs → live/completion.mjs} +1 -0
- package/dist/builtin/workflows/skills/impeccable/scripts/{live-event-validation.mjs → live/event-validation.mjs} +6 -5
- package/dist/builtin/workflows/skills/impeccable/scripts/live/manual-apply.mjs +939 -0
- package/dist/builtin/workflows/skills/impeccable/scripts/live/manual-edit-routes.mjs +357 -0
- package/dist/builtin/workflows/skills/impeccable/scripts/{live-manual-edits-buffer.mjs → live/manual-edits-buffer.mjs} +1 -1
- package/dist/builtin/workflows/skills/impeccable/scripts/{live-session-store.mjs → live/session-store.mjs} +21 -3
- package/dist/builtin/workflows/skills/impeccable/scripts/live/svelte-component.mjs +835 -0
- package/dist/builtin/workflows/skills/impeccable/scripts/live/sveltekit-adapter.mjs +274 -0
- package/dist/builtin/workflows/skills/impeccable/scripts/live/ui-core.mjs +180 -0
- package/dist/builtin/workflows/skills/impeccable/scripts/live/vocabulary.mjs +36 -0
- package/dist/builtin/workflows/skills/impeccable/scripts/live-accept.mjs +185 -60
- package/dist/builtin/workflows/skills/impeccable/scripts/live-browser-dom.js +146 -0
- package/dist/builtin/workflows/skills/impeccable/scripts/live-browser.js +3369 -1026
- package/dist/builtin/workflows/skills/impeccable/scripts/live-commit-manual-edits.mjs +2 -2
- package/dist/builtin/workflows/skills/impeccable/scripts/live-complete.mjs +2 -2
- package/dist/builtin/workflows/skills/impeccable/scripts/live-discard-manual-edits.mjs +1 -1
- package/dist/builtin/workflows/skills/impeccable/scripts/live-inject.mjs +133 -9
- package/dist/builtin/workflows/skills/impeccable/scripts/live-insert.mjs +42 -2
- package/dist/builtin/workflows/skills/impeccable/scripts/live-manual-edit-evidence.mjs +4 -4
- package/dist/builtin/workflows/skills/impeccable/scripts/live-poll.mjs +21 -15
- package/dist/builtin/workflows/skills/impeccable/scripts/live-resume.mjs +1 -1
- package/dist/builtin/workflows/skills/impeccable/scripts/live-server.mjs +205 -1269
- package/dist/builtin/workflows/skills/impeccable/scripts/live-status.mjs +2 -2
- package/dist/builtin/workflows/skills/impeccable/scripts/live-target.mjs +30 -0
- package/dist/builtin/workflows/skills/impeccable/scripts/live-wrap.mjs +69 -26
- package/dist/builtin/workflows/skills/impeccable/scripts/live.mjs +73 -22
- package/dist/core/atomic-guide-command.d.ts.map +1 -1
- package/dist/core/atomic-guide-command.js +5 -5
- package/dist/core/atomic-guide-command.js.map +1 -1
- package/docs/index.md +2 -2
- package/docs/quickstart.md +9 -9
- package/docs/workflows.md +42 -23
- package/package.json +2 -2
- package/dist/builtin/workflows/skills/impeccable/scripts/cleanup-deprecated.mjs +0 -284
- package/dist/builtin/workflows/skills/impeccable/scripts/impeccable-paths.mjs +0 -126
- /package/dist/builtin/workflows/skills/impeccable/scripts/{live-insert-ui.mjs → live/insert-ui.mjs} +0 -0
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { resolveProjectRoot } from '../context.mjs';
|
|
4
|
+
|
|
5
|
+
export const IMPECCABLE_DIR = '.impeccable';
|
|
6
|
+
export const LIVE_DIR = 'live';
|
|
7
|
+
export const CRITIQUE_DIR = 'critique';
|
|
8
|
+
|
|
9
|
+
export function getImpeccableDir(cwd = process.cwd(), options = {}) {
|
|
10
|
+
return path.join(resolveProjectRoot(cwd, options), IMPECCABLE_DIR);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function getDesignSidecarPath(cwd = process.cwd(), options = {}) {
|
|
14
|
+
return path.join(getImpeccableDir(cwd, options), 'design.json');
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function getDesignSidecarCandidates(cwd = process.cwd(), contextDir = cwd, options = {}) {
|
|
18
|
+
const projectRoot = resolveProjectRoot(cwd, options);
|
|
19
|
+
const candidates = [
|
|
20
|
+
getDesignSidecarPath(cwd, options),
|
|
21
|
+
path.join(projectRoot, 'DESIGN.json'),
|
|
22
|
+
];
|
|
23
|
+
const contextLegacy = path.join(contextDir, 'DESIGN.json');
|
|
24
|
+
if (!candidates.includes(contextLegacy)) candidates.push(contextLegacy);
|
|
25
|
+
return candidates;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function resolveDesignSidecarPath(cwd = process.cwd(), contextDir = cwd, options = {}) {
|
|
29
|
+
return firstExisting(getDesignSidecarCandidates(cwd, contextDir, options));
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function getLiveDir(cwd = process.cwd(), options = {}) {
|
|
33
|
+
return path.join(getImpeccableDir(cwd, options), LIVE_DIR);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function getLiveConfigPath(cwd = process.cwd(), options = {}) {
|
|
37
|
+
return path.join(getLiveDir(cwd, options), 'config.json');
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function getLegacyLiveConfigPath(scriptsDir) {
|
|
41
|
+
return path.join(scriptsDir, 'config.json');
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function resolveLiveConfigPath({ cwd = process.cwd(), scriptsDir, env = process.env, targetPath } = {}) {
|
|
45
|
+
if (env.IMPECCABLE_LIVE_CONFIG && env.IMPECCABLE_LIVE_CONFIG.trim()) {
|
|
46
|
+
const configured = env.IMPECCABLE_LIVE_CONFIG.trim();
|
|
47
|
+
return path.isAbsolute(configured) ? configured : path.resolve(cwd, configured);
|
|
48
|
+
}
|
|
49
|
+
const primary = getLiveConfigPath(cwd, { targetPath });
|
|
50
|
+
if (fs.existsSync(primary)) return primary;
|
|
51
|
+
if (scriptsDir) {
|
|
52
|
+
const legacy = getLegacyLiveConfigPath(scriptsDir);
|
|
53
|
+
if (fs.existsSync(legacy)) return legacy;
|
|
54
|
+
}
|
|
55
|
+
return primary;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export function getLiveServerPath(cwd = process.cwd(), options = {}) {
|
|
59
|
+
return path.join(getLiveDir(cwd, options), 'server.json');
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export function getLegacyLiveServerPath(cwd = process.cwd(), options = {}) {
|
|
63
|
+
return path.join(resolveProjectRoot(cwd, options), '.impeccable-live.json');
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export function readLiveServerInfo(cwd = process.cwd(), options = {}) {
|
|
67
|
+
for (const filePath of [getLiveServerPath(cwd, options), getLegacyLiveServerPath(cwd, options)]) {
|
|
68
|
+
try {
|
|
69
|
+
const info = JSON.parse(fs.readFileSync(filePath, 'utf-8'));
|
|
70
|
+
if (info && typeof info.pid === 'number' && !isLiveServerPidReachable(info.pid)) {
|
|
71
|
+
try { fs.unlinkSync(filePath); } catch {}
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
return { info, path: filePath };
|
|
75
|
+
} catch {
|
|
76
|
+
/* try next */
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export function isLiveServerPidReachable(pid) {
|
|
83
|
+
try {
|
|
84
|
+
process.kill(pid, 0);
|
|
85
|
+
return true;
|
|
86
|
+
} catch (err) {
|
|
87
|
+
// ESRCH means "no such process". EPERM means the process exists but this
|
|
88
|
+
// user cannot signal it, so the live server info is still valid.
|
|
89
|
+
return err?.code !== 'ESRCH';
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export function writeLiveServerInfo(cwd = process.cwd(), info, options = {}) {
|
|
94
|
+
const filePath = getLiveServerPath(cwd, options);
|
|
95
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
96
|
+
fs.writeFileSync(filePath, JSON.stringify(info));
|
|
97
|
+
return filePath;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export function removeLiveServerInfo(cwd = process.cwd(), options = {}) {
|
|
101
|
+
for (const filePath of [getLiveServerPath(cwd, options), getLegacyLiveServerPath(cwd, options)]) {
|
|
102
|
+
try { fs.unlinkSync(filePath); } catch {}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export function getLiveSessionsDir(cwd = process.cwd(), options = {}) {
|
|
107
|
+
return path.join(getLiveDir(cwd, options), 'sessions');
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export function getLegacyLiveSessionsDir(cwd = process.cwd(), options = {}) {
|
|
111
|
+
return path.join(resolveProjectRoot(cwd, options), '.impeccable-live', 'sessions');
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export function getLiveAnnotationsDir(cwd = process.cwd(), options = {}) {
|
|
115
|
+
return path.join(getLiveDir(cwd, options), 'annotations');
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export function getCritiqueDir(cwd = process.cwd(), options = {}) {
|
|
119
|
+
return path.join(getImpeccableDir(cwd, options), CRITIQUE_DIR);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export function getLegacyLiveAnnotationsDir(cwd = process.cwd(), options = {}) {
|
|
123
|
+
return path.join(resolveProjectRoot(cwd, options), '.impeccable-live', 'annotations');
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function firstExisting(paths) {
|
|
127
|
+
return paths.find((filePath) => fs.existsSync(filePath)) || null;
|
|
128
|
+
}
|
package/dist/builtin/workflows/skills/impeccable/scripts/{is-generated.mjs → lib/is-generated.mjs}
RENAMED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
* within the first ~300 characters — catches non-git projects.
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
|
-
import {
|
|
16
|
+
import { execFileSync } from 'node:child_process';
|
|
17
17
|
import fs from 'node:fs';
|
|
18
18
|
import path from 'node:path';
|
|
19
19
|
|
|
@@ -41,7 +41,7 @@ export function isGeneratedFile(filePath, options = {}) {
|
|
|
41
41
|
|
|
42
42
|
function isGitIgnored(absPath, cwd) {
|
|
43
43
|
try {
|
|
44
|
-
|
|
44
|
+
execFileSync('git', ['check-ignore', '--quiet', absPath], {
|
|
45
45
|
cwd,
|
|
46
46
|
stdio: 'ignore',
|
|
47
47
|
});
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
class TargetArgError extends Error {
|
|
2
|
+
constructor(message, code) {
|
|
3
|
+
super(message);
|
|
4
|
+
this.name = 'TargetArgError';
|
|
5
|
+
this.code = code;
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function parseTargetPath(args = [], { strict = false } = {}) {
|
|
10
|
+
let targetPath = null;
|
|
11
|
+
for (let i = 0; i < args.length; i++) {
|
|
12
|
+
const arg = String(args[i]);
|
|
13
|
+
if (arg === '--target' || arg === '-t') {
|
|
14
|
+
const next = args[i + 1];
|
|
15
|
+
if (next && !String(next).startsWith('-')) {
|
|
16
|
+
targetPath = String(next);
|
|
17
|
+
i++;
|
|
18
|
+
continue;
|
|
19
|
+
}
|
|
20
|
+
if (strict) {
|
|
21
|
+
throw new TargetArgError('--target requires a path value.', 'TARGET_VALUE_MISSING');
|
|
22
|
+
}
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
if (arg.startsWith('--target=')) {
|
|
26
|
+
const value = arg.slice('--target='.length);
|
|
27
|
+
if (value) {
|
|
28
|
+
targetPath = value;
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
if (strict) {
|
|
32
|
+
throw new TargetArgError('--target requires a path value.', 'TARGET_VALUE_MISSING');
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return targetPath;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function parseTargetOptions(args = [], options = {}) {
|
|
40
|
+
const targetPath = parseTargetPath(args, options);
|
|
41
|
+
return targetPath ? { targetPath } : {};
|
|
42
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
|
|
4
|
+
export const LIVE_BROWSER_SCRIPT_PARTS = Object.freeze([
|
|
5
|
+
Object.freeze({ name: 'session-state', file: 'live-browser-session.js' }),
|
|
6
|
+
Object.freeze({ name: 'dom-helpers', file: 'live-browser-dom.js' }),
|
|
7
|
+
Object.freeze({ name: 'browser-ui', file: 'live-browser.js' }),
|
|
8
|
+
]);
|
|
9
|
+
|
|
10
|
+
export function resolveLiveBrowserScriptParts(scriptsDir, parts = LIVE_BROWSER_SCRIPT_PARTS) {
|
|
11
|
+
if (!scriptsDir) throw new Error('scriptsDir is required');
|
|
12
|
+
return parts.map((part, index) => ({
|
|
13
|
+
...part,
|
|
14
|
+
index,
|
|
15
|
+
path: path.join(scriptsDir, part.file),
|
|
16
|
+
}));
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function assertLiveBrowserScriptParts(parts, exists = fs.existsSync) {
|
|
20
|
+
for (const part of parts) {
|
|
21
|
+
if (!exists(part.path)) {
|
|
22
|
+
throw new Error(`Live browser script part missing: ${part.name} (${part.path})`);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return parts;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function readLiveBrowserScriptParts(parts, readFile = (filePath) => fs.readFileSync(filePath, 'utf-8')) {
|
|
29
|
+
return parts.map((part) => ({
|
|
30
|
+
...part,
|
|
31
|
+
source: readFile(part.path),
|
|
32
|
+
}));
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function assembleLiveBrowserScript({ token, port, vocabulary, parts }) {
|
|
36
|
+
const prelude =
|
|
37
|
+
`window.__IMPECCABLE_TOKEN__ = '${token}';\n` +
|
|
38
|
+
`window.__IMPECCABLE_PORT__ = ${port};\n` +
|
|
39
|
+
// Canonical command vocabulary (values + labels + icons). live-browser.js
|
|
40
|
+
// builds its action picker from this instead of an inline copy.
|
|
41
|
+
`window.__IMPECCABLE_VOCAB__ = ${JSON.stringify(vocabulary)};\n`;
|
|
42
|
+
|
|
43
|
+
const body = parts.map((part) => {
|
|
44
|
+
const file = part.file || path.basename(part.path || '');
|
|
45
|
+
return `// --- impeccable live script part: ${part.name} (${file}) ---\n${part.source}`;
|
|
46
|
+
}).join('\n');
|
|
47
|
+
|
|
48
|
+
return prelude + body;
|
|
49
|
+
}
|
package/dist/builtin/workflows/skills/impeccable/scripts/{live-completion.mjs → live/completion.mjs}
RENAMED
|
@@ -3,6 +3,7 @@ export function completionTypeForAcceptResult(eventType, acceptResult) {
|
|
|
3
3
|
if (acceptResult?.handled === true && acceptResult?.carbonize === true) return 'agent_done';
|
|
4
4
|
if (acceptResult?.handled === true) return 'complete';
|
|
5
5
|
if (acceptResult?.mode === 'error') return 'error';
|
|
6
|
+
if (eventType === 'accept' && acceptResult?.previewMode === 'svelte-component') return 'error';
|
|
6
7
|
return 'agent_done';
|
|
7
8
|
}
|
|
8
9
|
|
|
@@ -3,12 +3,13 @@
|
|
|
3
3
|
* Extracted for unit testing (insert mode rules).
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import { canCreateInsert } from './
|
|
6
|
+
import { canCreateInsert } from './insert-ui.mjs';
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
// The accepted visual action values come from the canonical vocabulary so the
|
|
9
|
+
// validator, the picker UI, and the marketing demo never drift. Imported (not
|
|
10
|
+
// just re-exported) so it is also in scope for the validators below.
|
|
11
|
+
import { VISUAL_ACTIONS } from './vocabulary.mjs';
|
|
12
|
+
export { VISUAL_ACTIONS };
|
|
12
13
|
|
|
13
14
|
const ID_PATTERN = /^[0-9a-f]{8}$/;
|
|
14
15
|
const VARIANT_ID_PATTERN = /^[0-9]{1,3}$/;
|