@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
|
@@ -1,284 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* Cleans up deprecated Impeccable skill files, symlinks, and
|
|
4
|
-
* skills-lock.json entries left over from previous versions.
|
|
5
|
-
*
|
|
6
|
-
* Safe to run repeatedly -- it is a no-op when nothing needs cleaning.
|
|
7
|
-
*
|
|
8
|
-
* Usage (from the project root):
|
|
9
|
-
* node {{scripts_path}}/cleanup-deprecated.mjs
|
|
10
|
-
*
|
|
11
|
-
* What it does:
|
|
12
|
-
* 1. Finds every harness-specific skills directory (.claude/skills,
|
|
13
|
-
* .cursor/skills, .agents/skills, etc.).
|
|
14
|
-
* 2. For each deprecated skill name (with and without i- prefix),
|
|
15
|
-
* checks if the directory exists and its SKILL.md mentions
|
|
16
|
-
* "impeccable" (to avoid deleting unrelated user skills).
|
|
17
|
-
* 3. Deletes confirmed matches (files, directories, or symlinks).
|
|
18
|
-
* 4. Removes the corresponding entries from skills-lock.json.
|
|
19
|
-
*/
|
|
20
|
-
|
|
21
|
-
import { existsSync, readFileSync, writeFileSync, rmSync, readdirSync, statSync, lstatSync, unlinkSync } from 'node:fs';
|
|
22
|
-
import { join, resolve } from 'node:path';
|
|
23
|
-
|
|
24
|
-
// Skills that were renamed, merged, or folded in v2.0, v2.1, and v3.0.
|
|
25
|
-
const DEPRECATED_NAMES = [
|
|
26
|
-
// v2.0 renames
|
|
27
|
-
'frontend-design', // renamed to impeccable
|
|
28
|
-
'teach-impeccable', // folded into /impeccable init
|
|
29
|
-
// v2.1 merges
|
|
30
|
-
'arrange', // renamed to layout
|
|
31
|
-
'normalize', // merged into polish
|
|
32
|
-
'onboard', // merged into harden
|
|
33
|
-
'extract', // merged into /impeccable extract
|
|
34
|
-
// v3.0 consolidation: all standalone skills -> /impeccable sub-commands
|
|
35
|
-
'adapt',
|
|
36
|
-
'animate',
|
|
37
|
-
'audit',
|
|
38
|
-
'bolder',
|
|
39
|
-
'clarify',
|
|
40
|
-
'colorize',
|
|
41
|
-
'critique',
|
|
42
|
-
'delight',
|
|
43
|
-
'distill',
|
|
44
|
-
'harden',
|
|
45
|
-
'layout',
|
|
46
|
-
'optimize',
|
|
47
|
-
'overdrive',
|
|
48
|
-
'polish',
|
|
49
|
-
'quieter',
|
|
50
|
-
'shape',
|
|
51
|
-
'typeset',
|
|
52
|
-
];
|
|
53
|
-
|
|
54
|
-
// All known harness directories that may contain a skills/ subfolder.
|
|
55
|
-
const HARNESS_DIRS = [
|
|
56
|
-
'.claude', '.cursor', '.gemini', '.codex', '.agents',
|
|
57
|
-
'.trae', '.trae-cn', '.pi', '.opencode', '.kiro', '.rovodev',
|
|
58
|
-
];
|
|
59
|
-
|
|
60
|
-
// Per-skill fingerprints for SKILL.md bodies that never mentioned
|
|
61
|
-
// "impeccable" in their v2.x source. Used as a last-resort match
|
|
62
|
-
// when no skills-lock.json exists and the word heuristic fails.
|
|
63
|
-
// The strings are lifted verbatim from the v2.x frontmatter
|
|
64
|
-
// descriptions, so collisions with hand-written user skills are
|
|
65
|
-
// vanishingly unlikely.
|
|
66
|
-
const SKILL_FINGERPRINTS = {
|
|
67
|
-
harden: 'Make interfaces production-ready: error handling, empty states',
|
|
68
|
-
optimize: 'Diagnoses and fixes UI performance across loading speed',
|
|
69
|
-
};
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* Walk up from startDir until we find a directory that looks like a
|
|
73
|
-
* project root (has package.json, .git, or skills-lock.json).
|
|
74
|
-
*/
|
|
75
|
-
export function findProjectRoot(startDir = process.cwd()) {
|
|
76
|
-
let dir = resolve(startDir);
|
|
77
|
-
const { root } = { root: '/' };
|
|
78
|
-
while (dir !== root) {
|
|
79
|
-
if (
|
|
80
|
-
existsSync(join(dir, 'package.json')) ||
|
|
81
|
-
existsSync(join(dir, '.git')) ||
|
|
82
|
-
existsSync(join(dir, 'skills-lock.json'))
|
|
83
|
-
) {
|
|
84
|
-
return dir;
|
|
85
|
-
}
|
|
86
|
-
const parent = resolve(dir, '..');
|
|
87
|
-
if (parent === dir) break;
|
|
88
|
-
dir = parent;
|
|
89
|
-
}
|
|
90
|
-
return resolve(startDir);
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
/**
|
|
94
|
-
* Load skills-lock.json from the project root, or null if missing/unreadable.
|
|
95
|
-
*/
|
|
96
|
-
export function loadLock(projectRoot) {
|
|
97
|
-
const lockPath = join(projectRoot, 'skills-lock.json');
|
|
98
|
-
if (!existsSync(lockPath)) return null;
|
|
99
|
-
try {
|
|
100
|
-
return JSON.parse(readFileSync(lockPath, 'utf-8'));
|
|
101
|
-
} catch {
|
|
102
|
-
return null;
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
/**
|
|
107
|
-
* Check whether a skill directory belongs to Impeccable. Three layered
|
|
108
|
-
* signals, in order of reliability:
|
|
109
|
-
* 1. Lock source equals "pbakaus/impeccable" (authoritative).
|
|
110
|
-
* 2. SKILL.md body contains the word "impeccable".
|
|
111
|
-
* 3. SKILL.md body contains a per-skill fingerprint (for harden and
|
|
112
|
-
* optimize, whose v2.x SKILL.md never mentioned the pack name).
|
|
113
|
-
*/
|
|
114
|
-
export function isImpeccableSkill(skillDir, { skillName, lock } = {}) {
|
|
115
|
-
// 1. Authoritative: the lock file claims this skill is ours.
|
|
116
|
-
if (skillName && lock?.skills?.[skillName]?.source === 'pbakaus/impeccable') {
|
|
117
|
-
return true;
|
|
118
|
-
}
|
|
119
|
-
const skillMd = join(skillDir, 'SKILL.md');
|
|
120
|
-
if (!existsSync(skillMd)) return false;
|
|
121
|
-
let content;
|
|
122
|
-
try {
|
|
123
|
-
content = readFileSync(skillMd, 'utf-8');
|
|
124
|
-
} catch {
|
|
125
|
-
return false;
|
|
126
|
-
}
|
|
127
|
-
// 2. Word-level content heuristic.
|
|
128
|
-
if (/impeccable/i.test(content)) return true;
|
|
129
|
-
// 3. Per-skill fingerprint for old skills that never mentioned the pack.
|
|
130
|
-
// Strip the i- prefix so both `harden` and `i-harden` resolve to the
|
|
131
|
-
// same fingerprint entry.
|
|
132
|
-
const unprefixed = skillName?.startsWith('i-') ? skillName.slice(2) : skillName;
|
|
133
|
-
const fingerprint = unprefixed && SKILL_FINGERPRINTS[unprefixed];
|
|
134
|
-
if (fingerprint && content.includes(fingerprint)) return true;
|
|
135
|
-
return false;
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
/**
|
|
139
|
-
* Build the full list of names to check: each deprecated name, plus
|
|
140
|
-
* its i-prefixed variant.
|
|
141
|
-
*/
|
|
142
|
-
export function buildTargetNames() {
|
|
143
|
-
const names = [];
|
|
144
|
-
for (const name of DEPRECATED_NAMES) {
|
|
145
|
-
names.push(name);
|
|
146
|
-
names.push(`i-${name}`);
|
|
147
|
-
}
|
|
148
|
-
return names;
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
/**
|
|
152
|
-
* Find every skills directory across all harness dirs in the project.
|
|
153
|
-
* Returns absolute paths that exist on disk.
|
|
154
|
-
*/
|
|
155
|
-
export function findSkillsDirs(projectRoot) {
|
|
156
|
-
const dirs = [];
|
|
157
|
-
for (const harness of HARNESS_DIRS) {
|
|
158
|
-
const candidate = join(projectRoot, harness, 'skills');
|
|
159
|
-
if (existsSync(candidate)) {
|
|
160
|
-
dirs.push(candidate);
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
return dirs;
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
/**
|
|
167
|
-
* Remove deprecated skill directories/symlinks from all harness dirs.
|
|
168
|
-
* Reads skills-lock.json so the authoritative "source" field can
|
|
169
|
-
* drive deletion even when SKILL.md never mentions impeccable.
|
|
170
|
-
* Returns an array of paths that were deleted.
|
|
171
|
-
*/
|
|
172
|
-
export function removeDeprecatedSkills(projectRoot, lock) {
|
|
173
|
-
if (lock === undefined) lock = loadLock(projectRoot);
|
|
174
|
-
const targets = buildTargetNames();
|
|
175
|
-
const skillsDirs = findSkillsDirs(projectRoot);
|
|
176
|
-
const deleted = [];
|
|
177
|
-
|
|
178
|
-
for (const skillsDir of skillsDirs) {
|
|
179
|
-
for (const name of targets) {
|
|
180
|
-
const skillPath = join(skillsDir, name);
|
|
181
|
-
|
|
182
|
-
// Use lstat to detect symlinks (existsSync follows symlinks and
|
|
183
|
-
// returns false for dangling ones).
|
|
184
|
-
let stat;
|
|
185
|
-
try {
|
|
186
|
-
stat = lstatSync(skillPath);
|
|
187
|
-
} catch {
|
|
188
|
-
continue; // does not exist at all
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
if (stat.isSymbolicLink()) {
|
|
192
|
-
// Symlink: check the target if it's alive, otherwise treat
|
|
193
|
-
// dangling symlinks to deprecated names as safe to remove.
|
|
194
|
-
const targetAlive = existsSync(skillPath);
|
|
195
|
-
const isMatch = targetAlive
|
|
196
|
-
? isImpeccableSkill(skillPath, { skillName: name, lock })
|
|
197
|
-
: true;
|
|
198
|
-
if (isMatch) {
|
|
199
|
-
unlinkSync(skillPath);
|
|
200
|
-
deleted.push(skillPath);
|
|
201
|
-
}
|
|
202
|
-
continue;
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
// Regular directory -- verify it belongs to impeccable
|
|
206
|
-
if (isImpeccableSkill(skillPath, { skillName: name, lock })) {
|
|
207
|
-
rmSync(skillPath, { recursive: true, force: true });
|
|
208
|
-
deleted.push(skillPath);
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
return deleted;
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
/**
|
|
217
|
-
* Remove deprecated entries from skills-lock.json.
|
|
218
|
-
* Only removes entries whose source is "pbakaus/impeccable".
|
|
219
|
-
* Returns the list of removed skill names.
|
|
220
|
-
*/
|
|
221
|
-
export function cleanSkillsLock(projectRoot) {
|
|
222
|
-
const lockPath = join(projectRoot, 'skills-lock.json');
|
|
223
|
-
if (!existsSync(lockPath)) return [];
|
|
224
|
-
|
|
225
|
-
let lock;
|
|
226
|
-
try {
|
|
227
|
-
lock = JSON.parse(readFileSync(lockPath, 'utf-8'));
|
|
228
|
-
} catch {
|
|
229
|
-
return [];
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
if (!lock.skills || typeof lock.skills !== 'object') return [];
|
|
233
|
-
|
|
234
|
-
const targets = buildTargetNames();
|
|
235
|
-
const removed = [];
|
|
236
|
-
|
|
237
|
-
for (const name of targets) {
|
|
238
|
-
const entry = lock.skills[name];
|
|
239
|
-
if (!entry) continue;
|
|
240
|
-
// Only remove if it belongs to impeccable
|
|
241
|
-
if (entry.source === 'pbakaus/impeccable') {
|
|
242
|
-
delete lock.skills[name];
|
|
243
|
-
removed.push(name);
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
if (removed.length > 0) {
|
|
248
|
-
writeFileSync(lockPath, JSON.stringify(lock, null, 2) + '\n', 'utf-8');
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
return removed;
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
/**
|
|
255
|
-
* Run the full cleanup. Returns a summary object.
|
|
256
|
-
*
|
|
257
|
-
* Order matters: read the lock and delete directories first, then
|
|
258
|
-
* strip lock entries. Otherwise the authoritative signal is gone by
|
|
259
|
-
* the time directory deletion runs.
|
|
260
|
-
*/
|
|
261
|
-
export function cleanup(projectRoot) {
|
|
262
|
-
const root = projectRoot || findProjectRoot();
|
|
263
|
-
const lock = loadLock(root);
|
|
264
|
-
const deletedPaths = removeDeprecatedSkills(root, lock);
|
|
265
|
-
const removedLockEntries = cleanSkillsLock(root);
|
|
266
|
-
return { deletedPaths, removedLockEntries, projectRoot: root };
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
// CLI entry point
|
|
270
|
-
if (process.argv[1] && resolve(process.argv[1]) === resolve(new URL(import.meta.url).pathname)) {
|
|
271
|
-
const result = cleanup();
|
|
272
|
-
if (result.deletedPaths.length === 0 && result.removedLockEntries.length === 0) {
|
|
273
|
-
console.log('No deprecated Impeccable skills found. Nothing to clean up.');
|
|
274
|
-
} else {
|
|
275
|
-
if (result.deletedPaths.length > 0) {
|
|
276
|
-
console.log(`Removed ${result.deletedPaths.length} deprecated skill(s):`);
|
|
277
|
-
for (const p of result.deletedPaths) console.log(` - ${p}`);
|
|
278
|
-
}
|
|
279
|
-
if (result.removedLockEntries.length > 0) {
|
|
280
|
-
console.log(`Cleaned ${result.removedLockEntries.length} entry/entries from skills-lock.json:`);
|
|
281
|
-
for (const name of result.removedLockEntries) console.log(` - ${name}`);
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
}
|
|
@@ -1,126 +0,0 @@
|
|
|
1
|
-
import fs from 'node:fs';
|
|
2
|
-
import path from 'node:path';
|
|
3
|
-
|
|
4
|
-
export const IMPECCABLE_DIR = '.impeccable';
|
|
5
|
-
export const LIVE_DIR = 'live';
|
|
6
|
-
export const CRITIQUE_DIR = 'critique';
|
|
7
|
-
|
|
8
|
-
export function getImpeccableDir(cwd = process.cwd()) {
|
|
9
|
-
return path.join(cwd, IMPECCABLE_DIR);
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export function getDesignSidecarPath(cwd = process.cwd()) {
|
|
13
|
-
return path.join(getImpeccableDir(cwd), 'design.json');
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export function getDesignSidecarCandidates(cwd = process.cwd(), contextDir = cwd) {
|
|
17
|
-
const candidates = [
|
|
18
|
-
getDesignSidecarPath(cwd),
|
|
19
|
-
path.join(cwd, 'DESIGN.json'),
|
|
20
|
-
];
|
|
21
|
-
const contextLegacy = path.join(contextDir, 'DESIGN.json');
|
|
22
|
-
if (!candidates.includes(contextLegacy)) candidates.push(contextLegacy);
|
|
23
|
-
return candidates;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export function resolveDesignSidecarPath(cwd = process.cwd(), contextDir = cwd) {
|
|
27
|
-
return firstExisting(getDesignSidecarCandidates(cwd, contextDir));
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export function getLiveDir(cwd = process.cwd()) {
|
|
31
|
-
return path.join(getImpeccableDir(cwd), LIVE_DIR);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
export function getLiveConfigPath(cwd = process.cwd()) {
|
|
35
|
-
return path.join(getLiveDir(cwd), 'config.json');
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export function getLegacyLiveConfigPath(scriptsDir) {
|
|
39
|
-
return path.join(scriptsDir, 'config.json');
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
export function resolveLiveConfigPath({ cwd = process.cwd(), scriptsDir, env = process.env } = {}) {
|
|
43
|
-
if (env.IMPECCABLE_LIVE_CONFIG && env.IMPECCABLE_LIVE_CONFIG.trim()) {
|
|
44
|
-
const configured = env.IMPECCABLE_LIVE_CONFIG.trim();
|
|
45
|
-
return path.isAbsolute(configured) ? configured : path.resolve(cwd, configured);
|
|
46
|
-
}
|
|
47
|
-
const primary = getLiveConfigPath(cwd);
|
|
48
|
-
if (fs.existsSync(primary)) return primary;
|
|
49
|
-
if (scriptsDir) {
|
|
50
|
-
const legacy = getLegacyLiveConfigPath(scriptsDir);
|
|
51
|
-
if (fs.existsSync(legacy)) return legacy;
|
|
52
|
-
}
|
|
53
|
-
return primary;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
export function getLiveServerPath(cwd = process.cwd()) {
|
|
57
|
-
return path.join(getLiveDir(cwd), 'server.json');
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
export function getLegacyLiveServerPath(cwd = process.cwd()) {
|
|
61
|
-
return path.join(cwd, '.impeccable-live.json');
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
export function readLiveServerInfo(cwd = process.cwd()) {
|
|
65
|
-
for (const filePath of [getLiveServerPath(cwd), getLegacyLiveServerPath(cwd)]) {
|
|
66
|
-
try {
|
|
67
|
-
const info = JSON.parse(fs.readFileSync(filePath, 'utf-8'));
|
|
68
|
-
if (info && typeof info.pid === 'number' && !isLiveServerPidReachable(info.pid)) {
|
|
69
|
-
try { fs.unlinkSync(filePath); } catch {}
|
|
70
|
-
continue;
|
|
71
|
-
}
|
|
72
|
-
return { info, path: filePath };
|
|
73
|
-
} catch {
|
|
74
|
-
/* try next */
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
return null;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
export function isLiveServerPidReachable(pid) {
|
|
81
|
-
try {
|
|
82
|
-
process.kill(pid, 0);
|
|
83
|
-
return true;
|
|
84
|
-
} catch (err) {
|
|
85
|
-
// ESRCH means "no such process". EPERM means the process exists but this
|
|
86
|
-
// user cannot signal it, so the live server info is still valid.
|
|
87
|
-
return err?.code !== 'ESRCH';
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
export function writeLiveServerInfo(cwd = process.cwd(), info) {
|
|
92
|
-
const filePath = getLiveServerPath(cwd);
|
|
93
|
-
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
94
|
-
fs.writeFileSync(filePath, JSON.stringify(info));
|
|
95
|
-
return filePath;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
export function removeLiveServerInfo(cwd = process.cwd()) {
|
|
99
|
-
for (const filePath of [getLiveServerPath(cwd), getLegacyLiveServerPath(cwd)]) {
|
|
100
|
-
try { fs.unlinkSync(filePath); } catch {}
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
export function getLiveSessionsDir(cwd = process.cwd()) {
|
|
105
|
-
return path.join(getLiveDir(cwd), 'sessions');
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
export function getLegacyLiveSessionsDir(cwd = process.cwd()) {
|
|
109
|
-
return path.join(cwd, '.impeccable-live', 'sessions');
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
export function getLiveAnnotationsDir(cwd = process.cwd()) {
|
|
113
|
-
return path.join(getLiveDir(cwd), 'annotations');
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
export function getCritiqueDir(cwd = process.cwd()) {
|
|
117
|
-
return path.join(getImpeccableDir(cwd), CRITIQUE_DIR);
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
export function getLegacyLiveAnnotationsDir(cwd = process.cwd()) {
|
|
121
|
-
return path.join(cwd, '.impeccable-live', 'annotations');
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
function firstExisting(paths) {
|
|
125
|
-
return paths.find((filePath) => fs.existsSync(filePath)) || null;
|
|
126
|
-
}
|
/package/dist/builtin/workflows/skills/impeccable/scripts/{live-insert-ui.mjs → live/insert-ui.mjs}
RENAMED
|
File without changes
|