wize-dev-kit 0.26.1 → 0.27.2
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/ARCH.md +2 -1
- package/CHANGELOG.md +64 -0
- package/README.es.md +28 -6
- package/README.md +28 -6
- package/README.pt-BR.md +28 -6
- package/adapters/continue/render.js +2 -3
- package/adapters/copilot/render.js +3 -3
- package/adapters/cursor/render.js +2 -3
- package/adapters/generic/render.js +2 -3
- package/adapters/opencode/render.js +3 -4
- package/adapters/windsurf/render.js +2 -3
- package/docs/WORKTREES.md +150 -0
- package/docs/WORKTREES.pt-BR.md +150 -0
- package/docs/harnesses/antigravity.md +2 -0
- package/docs/harnesses/antigravity.pt-BR.md +2 -0
- package/docs/harnesses/claude-code.md +2 -0
- package/docs/harnesses/claude-code.pt-BR.md +2 -0
- package/docs/harnesses/codex.md +3 -1
- package/docs/harnesses/codex.pt-BR.md +3 -1
- package/docs/harnesses/continue.md +2 -0
- package/docs/harnesses/continue.pt-BR.md +2 -0
- package/docs/harnesses/copilot.md +2 -0
- package/docs/harnesses/copilot.pt-BR.md +2 -0
- package/docs/harnesses/cursor.md +2 -0
- package/docs/harnesses/cursor.pt-BR.md +2 -0
- package/docs/harnesses/generic.md +2 -0
- package/docs/harnesses/generic.pt-BR.md +2 -0
- package/docs/harnesses/hermes.md +2 -0
- package/docs/harnesses/hermes.pt-BR.md +2 -0
- package/docs/harnesses/kimi-code.md +2 -0
- package/docs/harnesses/kimi-code.pt-BR.md +2 -0
- package/docs/harnesses/kiro.md +2 -0
- package/docs/harnesses/kiro.pt-BR.md +2 -0
- package/docs/harnesses/opencode.md +2 -0
- package/docs/harnesses/opencode.pt-BR.md +2 -0
- package/docs/harnesses/windsurf.md +2 -0
- package/docs/harnesses/windsurf.pt-BR.md +2 -0
- package/package.json +1 -1
- package/src/orchestrator-skills/module.yaml +1 -1
- package/src/orchestrator-skills/wize/skill.md +17 -7
- package/src/orchestrator-skills/wize-help/skill.md +20 -7
- package/src/orchestrator-skills/wize-update/skill.md +33 -27
- package/tools/installer/commands/doctor.js +186 -40
- package/tools/installer/commands/document-project.js +13 -3
- package/tools/installer/commands/hooks.js +215 -0
- package/tools/installer/commands/hydrate.js +298 -0
- package/tools/installer/commands/sync.js +50 -23
- package/tools/installer/commands/update.js +596 -120
- package/tools/installer/commands/version-check.js +69 -10
- package/tools/installer/document-project/modes/full-rescan.js +1 -1
- package/tools/installer/document-project/modes/initial-scan.js +5 -4
- package/tools/installer/document-project/modes/quick.js +11 -4
- package/tools/installer/git-context.js +219 -0
- package/tools/installer/git-ops.js +211 -0
- package/tools/installer/install-plan.js +136 -0
- package/tools/installer/marker.js +67 -0
- package/tools/installer/project-root.js +68 -0
- package/tools/installer/project-status.js +171 -0
- package/tools/installer/render-shared.js +170 -4
- package/tools/installer/render-targets.js +112 -0
- package/tools/installer/semver.js +59 -0
- package/tools/installer/setup-helpers.js +89 -31
- package/tools/installer/templates/hydrate.sh +163 -0
- package/tools/installer/templates/wize-kit-update.yml +38 -0
- package/tools/installer/toml.js +133 -0
- package/tools/installer/util.js +16 -0
- package/tools/installer/version-check.js +167 -37
- package/tools/installer/wize-cli.js +216 -78
- package/tools/installer/sync.js +0 -29
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
// `wize-dev-kit hydrate` — render this checkout from .wize/config/project.toml.
|
|
2
|
+
//
|
|
3
|
+
// Built for fresh worktrees (Orca, Claude Code, Codex, Cursor): no prompts,
|
|
4
|
+
// never reads stdin, never runs the baseline, never writes tracked files
|
|
5
|
+
// (project.toml, .gitignore, AGENTS.md, tea.toml, .wize/custom, artifacts,
|
|
6
|
+
// knowledge) and never runs a mutating git command. Always exits 0 so a
|
|
7
|
+
// failure cannot block worktree creation; --strict turns ok:false into 1.
|
|
8
|
+
|
|
9
|
+
'use strict';
|
|
10
|
+
|
|
11
|
+
const fs = require('node:fs');
|
|
12
|
+
const path = require('node:path');
|
|
13
|
+
const { spawnSync } = require('node:child_process');
|
|
14
|
+
const { loadProjectConfig } = require('../toml.js');
|
|
15
|
+
const { compareVersions, semverGreater, parse, safePin } = require('../semver.js');
|
|
16
|
+
const { gitContext, trackedSet, statusPorcelain } = require('../git-context.js');
|
|
17
|
+
const { renderTargets, missingTargets } = require('../render-targets.js');
|
|
18
|
+
const { readMarker, writeMarker, markerPin, fallbackExpired } = require('../marker.js');
|
|
19
|
+
const { deriveUserToml } = require('../setup-helpers.js');
|
|
20
|
+
const { getLatestNoWait, isCI } = require('../version-check.js');
|
|
21
|
+
const { HYDRATE_MIN, supportsHydrate } = require('../project-status.js');
|
|
22
|
+
const { real, sameSet } = require('../util.js');
|
|
23
|
+
|
|
24
|
+
const DELEGATE_ATTEMPTS = 2;
|
|
25
|
+
// Per attempt. A dropped network never fails fast (npm's fetch timeout does not
|
|
26
|
+
// cap the TCP connect), so a killed attempt is not retried; the cold-cache race
|
|
27
|
+
// that the second attempt absorbs fails quickly. Two cold attempts stay well
|
|
28
|
+
// under the 180 s SessionStart budget.
|
|
29
|
+
const DELEGATE_TIMEOUT_MS = 45000;
|
|
30
|
+
const DELEGATE_BACKOFF_MS = 2000;
|
|
31
|
+
|
|
32
|
+
const isFile = (p) => { try { return fs.statSync(p).isFile(); } catch { return false; } };
|
|
33
|
+
const lexists = (p) => { try { fs.lstatSync(p); return true; } catch { return false; } };
|
|
34
|
+
|
|
35
|
+
function sleepSync(ms) {
|
|
36
|
+
if (ms > 0) Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// user.toml is per-developer and git-ignored, so each checkout needs its own.
|
|
40
|
+
// Never overwrites. Sources in order: $ORCA_ROOT_PATH (only when it belongs to
|
|
41
|
+
// this repository), the primary checkout, then a file derived from git/$USER.
|
|
42
|
+
// -> 'present' | 'copied:<src>' | 'generated' | 'failed'
|
|
43
|
+
function ensureUserToml({ root, ctx, env }) {
|
|
44
|
+
const dest = path.join(root, '.wize', 'config', 'user.toml');
|
|
45
|
+
if (fs.existsSync(dest)) return 'present';
|
|
46
|
+
|
|
47
|
+
const candidates = [];
|
|
48
|
+
if (env.ORCA_ROOT_PATH && ctx.commonDir) {
|
|
49
|
+
const orcaRoot = real(env.ORCA_ROOT_PATH);
|
|
50
|
+
const theirs = gitContext(orcaRoot);
|
|
51
|
+
if (theirs.isRepo && theirs.commonDir && real(theirs.commonDir) === real(ctx.commonDir)) candidates.push(orcaRoot);
|
|
52
|
+
}
|
|
53
|
+
if (ctx.primary && real(ctx.primary) !== real(root)) candidates.push(ctx.primary);
|
|
54
|
+
|
|
55
|
+
try {
|
|
56
|
+
fs.mkdirSync(path.dirname(dest), { recursive: true });
|
|
57
|
+
for (const dir of candidates) {
|
|
58
|
+
const src = path.join(dir, '.wize', 'config', 'user.toml');
|
|
59
|
+
if (!isFile(src) || real(src) === real(dest)) continue;
|
|
60
|
+
try {
|
|
61
|
+
fs.copyFileSync(src, dest, fs.constants.COPYFILE_EXCL);
|
|
62
|
+
return `copied:${src}`;
|
|
63
|
+
} catch (err) {
|
|
64
|
+
if (err.code === 'EEXIST') return 'present';
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
fs.writeFileSync(dest, deriveUserToml(root, env), { encoding: 'utf-8', flag: 'wx' });
|
|
68
|
+
return 'generated';
|
|
69
|
+
} catch (err) {
|
|
70
|
+
return err.code === 'EEXIST' ? 'present' : 'failed';
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// No --root: the child runs with cwd = root, and a path with spaces or shell
|
|
75
|
+
// metacharacters would be split by cmd.exe on Windows (shell: true). --strict
|
|
76
|
+
// is always on, so a child that rendered nothing is not counted as success.
|
|
77
|
+
function forwardedFlags(flags) {
|
|
78
|
+
const out = ['--strict'];
|
|
79
|
+
for (const f of ['json', 'quiet', 'if-needed', 'no-notice']) if (flags[f]) out.push(`--${f}`);
|
|
80
|
+
return out;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Runs `npx wize-dev-kit@<pin> hydrate` so the checkout renders exactly the
|
|
84
|
+
// pinned kit. Two attempts absorb the cold-cache ENOTEMPTY race. An exact
|
|
85
|
+
// version is immutable, so a cached copy is used without revalidating the
|
|
86
|
+
// packument (offline, revalidation alone costs about 70 s), and npm's own fetch
|
|
87
|
+
// retries are off because the loop retries.
|
|
88
|
+
function delegate({ pin, root, flags, env, spawn, backoffMs, warn }) {
|
|
89
|
+
const npx = process.platform === 'win32' ? 'npx.cmd' : 'npx';
|
|
90
|
+
const args = ['--yes', '--prefer-offline', `wize-dev-kit@${pin}`, 'hydrate', ...forwardedFlags(flags)];
|
|
91
|
+
for (let attempt = 1; attempt <= DELEGATE_ATTEMPTS; attempt++) {
|
|
92
|
+
const r = spawn(npx, args, {
|
|
93
|
+
cwd: root,
|
|
94
|
+
env: {
|
|
95
|
+
npm_config_fetch_retries: '0',
|
|
96
|
+
npm_config_fetch_timeout: '20000',
|
|
97
|
+
...env,
|
|
98
|
+
// The child must render this root, not whatever ORCA_WORKTREE_PATH names.
|
|
99
|
+
WIZE_PROJECT_ROOT: root,
|
|
100
|
+
WIZE_HYDRATE_DELEGATED: '1', WIZE_SKIP_BASELINE: '1', WIZE_DISABLE_UPDATE_CHECK: '1'
|
|
101
|
+
},
|
|
102
|
+
timeout: DELEGATE_TIMEOUT_MS,
|
|
103
|
+
// --json needs exactly one object on stdout, so keep the child's output
|
|
104
|
+
// until it is known to have succeeded. stderr is held back too: a failed
|
|
105
|
+
// attempt would print npm's raw ETARGET/ENOTFOUND block once per attempt,
|
|
106
|
+
// and the caller prints one line instead (WIZE_VERBOSE=1 shows it all).
|
|
107
|
+
stdio: ['ignore', flags.json ? 'pipe' : 'inherit', env.WIZE_VERBOSE === '1' ? 'inherit' : 'pipe'],
|
|
108
|
+
encoding: 'utf-8',
|
|
109
|
+
shell: process.platform === 'win32'
|
|
110
|
+
});
|
|
111
|
+
if (r && !r.error && r.status === 0) {
|
|
112
|
+
if (typeof r.stderr === 'string' && r.stderr) warn(r.stderr.trimEnd());
|
|
113
|
+
return { ok: true, stdout: typeof r.stdout === 'string' ? r.stdout : '' };
|
|
114
|
+
}
|
|
115
|
+
const timedOut = !!(r && ((r.error && r.error.code === 'ETIMEDOUT') || (r.signal && !r.error)));
|
|
116
|
+
if (timedOut) break;
|
|
117
|
+
if (attempt < DELEGATE_ATTEMPTS) sleepSync(backoffMs);
|
|
118
|
+
}
|
|
119
|
+
return { ok: false };
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function cmdHydrate({ kitRoot, binary, projectRoot, flags = {}, env = process.env, log = console.log, warn = console.error, deps = {} } = {}) {
|
|
123
|
+
const spawn = deps.spawnSync || spawnSync;
|
|
124
|
+
const latestNoWait = deps.getLatestNoWait || getLatestNoWait;
|
|
125
|
+
const backoffMs = Number.isFinite(Number(env.WIZE_HYDRATE_BACKOFF_MS)) && env.WIZE_HYDRATE_BACKOFF_MS !== undefined
|
|
126
|
+
? Number(env.WIZE_HYDRATE_BACKOFF_MS) : DELEGATE_BACKOFF_MS;
|
|
127
|
+
const root = projectRoot;
|
|
128
|
+
const result = {
|
|
129
|
+
ok: true, root, linked: false, primary: null, pin: null, binary,
|
|
130
|
+
delegated: false, user_toml: null, adapters: [], warnings: [], notice: null
|
|
131
|
+
};
|
|
132
|
+
const say = (line) => { if (!flags.json) log(line); };
|
|
133
|
+
const chatter = (line) => { if (!flags.json && !flags.quiet) log(line); };
|
|
134
|
+
const warning = (line) => { result.warnings.push(line); warn(line); };
|
|
135
|
+
const emit = () => {
|
|
136
|
+
if (flags.json) log(JSON.stringify(result));
|
|
137
|
+
result.exitCode = flags.strict && !result.ok ? 1 : 0;
|
|
138
|
+
return result;
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
try {
|
|
142
|
+
if (!isFile(path.join(root, '.wize', 'config', 'project.toml'))) {
|
|
143
|
+
const bare = gitContext(root);
|
|
144
|
+
result.linked = bare.linked;
|
|
145
|
+
result.primary = bare.primary;
|
|
146
|
+
say('wize: no .wize/config/project.toml here, skipping');
|
|
147
|
+
// A delegated child that finds nothing to render must not read as success.
|
|
148
|
+
if (env.WIZE_HYDRATE_DELEGATED) result.ok = false;
|
|
149
|
+
return emit();
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const cfg = loadProjectConfig(root);
|
|
153
|
+
const targets = (cfg.install && cfg.install.ide_targets) || ['claude-code', 'generic'];
|
|
154
|
+
const profiles = (cfg.install && cfg.install.profiles) || ['core'];
|
|
155
|
+
const pin = (cfg.project && typeof cfg.project.kit_version === 'string' && cfg.project.kit_version) || null;
|
|
156
|
+
result.pin = pin;
|
|
157
|
+
|
|
158
|
+
const ctx = gitContext(root);
|
|
159
|
+
result.linked = ctx.linked;
|
|
160
|
+
result.primary = ctx.primary;
|
|
161
|
+
|
|
162
|
+
if (flags['if-needed']) {
|
|
163
|
+
const marker = readMarker(root);
|
|
164
|
+
const userToml = fs.existsSync(path.join(root, '.wize', 'config', 'user.toml'));
|
|
165
|
+
if (pin && marker && markerPin(marker) === pin && !fallbackExpired(marker)
|
|
166
|
+
&& sameSet(marker.targets || [], targets) && sameSet(marker.profiles || [], profiles)
|
|
167
|
+
&& userToml && missingTargets(root, targets).length === 0) {
|
|
168
|
+
result.user_toml = 'present';
|
|
169
|
+
result.adapters = [];
|
|
170
|
+
if (!flags.quiet) say(`wize: already hydrated (${pin})`);
|
|
171
|
+
return emit();
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
const before = statusPorcelain(root);
|
|
176
|
+
|
|
177
|
+
result.user_toml = ensureUserToml({ root, ctx, env });
|
|
178
|
+
if (result.user_toml === 'failed') warning('wize: could not create .wize/config/user.toml; copy it from your primary checkout');
|
|
179
|
+
|
|
180
|
+
const canDelegate = supportsHydrate(pin) && pin !== binary
|
|
181
|
+
&& !flags['no-delegate'] && !env.WIZE_HYDRATE_DELEGATED;
|
|
182
|
+
if (pin && !parse(pin)) {
|
|
183
|
+
warning(`wize: kit_version "${pin}" is not a version; rendering with ${binary}`);
|
|
184
|
+
} else if (pin && compareVersions(pin, HYDRATE_MIN) < 0) {
|
|
185
|
+
warning(`wize: pin ${pin} predates hydrate; adopt it with: npx wize-dev-kit@latest update`);
|
|
186
|
+
} else if (!pin) {
|
|
187
|
+
warning('wize: kit_version missing in project.toml; run: npx wize-dev-kit@latest update');
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
let delegated = false;
|
|
191
|
+
if (canDelegate) {
|
|
192
|
+
const d = delegate({ pin, root, flags, env, spawn, backoffMs, warn });
|
|
193
|
+
if (d.ok) {
|
|
194
|
+
delegated = true;
|
|
195
|
+
result.delegated = true;
|
|
196
|
+
if (flags.json) {
|
|
197
|
+
try {
|
|
198
|
+
const child = JSON.parse(d.stdout.trim());
|
|
199
|
+
if (Array.isArray(child.adapters)) result.adapters = child.adapters;
|
|
200
|
+
if (child.ok === false) result.ok = false;
|
|
201
|
+
if (Array.isArray(child.warnings)) result.warnings.push(...child.warnings);
|
|
202
|
+
} catch {
|
|
203
|
+
result.warnings.push('wize: delegated hydrate finished but its JSON output was unreadable');
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
} else {
|
|
207
|
+
warning(`wize: could not run kit ${pin} (offline or unpublished); rendering with ${binary}`);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
if (!delegated) {
|
|
212
|
+
// Fail closed: when git cannot say what is tracked (missing binary,
|
|
213
|
+
// "dubious ownership"), no existing file is overwritten.
|
|
214
|
+
const tracked = ctx.isRepo ? trackedSet(root) : new Set();
|
|
215
|
+
const failClosed = tracked === null;
|
|
216
|
+
// A write that lands outside the project (a symlinked directory leading
|
|
217
|
+
// into another directory or repository) is never allowed.
|
|
218
|
+
const rootReal = real(root);
|
|
219
|
+
const inside = (p) => [root, rootReal].some(r => p === r || p.startsWith(r + path.sep));
|
|
220
|
+
const guard = (abs) => !inside(abs) || (failClosed ? lexists(abs) : tracked.has(abs));
|
|
221
|
+
if (failClosed) warning('wize: git could not list tracked files (git missing or unsafe repository); existing files are left untouched');
|
|
222
|
+
const render = renderTargets({
|
|
223
|
+
kitRoot, projectRoot: root, targets, profiles,
|
|
224
|
+
guard,
|
|
225
|
+
skipAgentsMd: true
|
|
226
|
+
});
|
|
227
|
+
result.adapters = render.adapters;
|
|
228
|
+
for (const a of render.adapters) {
|
|
229
|
+
if (a.skipped) chatter(` - ${a.code}: skipped (${a.reason})`);
|
|
230
|
+
else if (a.error) chatter(` ✖ ${a.code}: ${a.error}`);
|
|
231
|
+
else chatter(` ✓ ${a.code}: ${a.written} written, ${a.unchanged} unchanged${a.skippedTracked.length ? `, ${a.skippedTracked.length} tracked skipped` : ''}`);
|
|
232
|
+
}
|
|
233
|
+
const failed = render.adapters.filter(a => a.error);
|
|
234
|
+
if (failed.length) {
|
|
235
|
+
result.ok = false;
|
|
236
|
+
for (const a of failed) result.warnings.push(`wize: adapter ${a.code} failed: ${a.error}`);
|
|
237
|
+
warn(`wize: hydrate: adapter ${failed.map(a => a.code).join(', ')} failed; run: npx --yes wize-dev-kit@${safePin(pin) || 'latest'} hydrate`);
|
|
238
|
+
}
|
|
239
|
+
const trackedSkipped = render.adapters.reduce((n, a) => n + a.skippedTracked.length, 0);
|
|
240
|
+
if (trackedSkipped && !failClosed) {
|
|
241
|
+
warning(`wize: ${trackedSkipped} generated file(s) are tracked by git or resolve outside the project and were left untouched; untrack them with: npx wize-dev-kit@latest update`);
|
|
242
|
+
}
|
|
243
|
+
if (!failed.length && !(failClosed && trackedSkipped)) {
|
|
244
|
+
writeMarker(root, {
|
|
245
|
+
kit_version: binary,
|
|
246
|
+
pin,
|
|
247
|
+
targets,
|
|
248
|
+
profiles,
|
|
249
|
+
counts: {
|
|
250
|
+
written: render.adapters.reduce((n, a) => n + a.written, 0),
|
|
251
|
+
unchanged: render.adapters.reduce((n, a) => n + a.unchanged, 0),
|
|
252
|
+
skipped_tracked: trackedSkipped
|
|
253
|
+
},
|
|
254
|
+
delegated: false,
|
|
255
|
+
rendered_with: binary,
|
|
256
|
+
fallback: canDelegate
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
// Safety net: whatever shows up in `git status` that was not there before
|
|
262
|
+
// means the .gitignore block is out of date. Nothing is reverted.
|
|
263
|
+
const after = statusPorcelain(root);
|
|
264
|
+
if (before && after) {
|
|
265
|
+
const known = new Set(before);
|
|
266
|
+
const fresh = after.filter(l => !known.has(l));
|
|
267
|
+
if (fresh.length) {
|
|
268
|
+
warning(`wize: hydrate left new or changed entries in git status: ${fresh.map(l => l.trim()).join(', ')}; your .gitignore block is outdated; run: npx wize-dev-kit@latest update`);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
// Notice: cache only, never blocks.
|
|
273
|
+
const quietNotice = flags['no-notice'] || flags.quiet || env.WIZE_DISABLE_UPDATE_CHECK === '1' || isCI(env);
|
|
274
|
+
if (!quietNotice && pin) {
|
|
275
|
+
// Without a terminal (an agent, an Orca setup script) no background refresh is started.
|
|
276
|
+
const isTTY = deps.isTTY !== undefined ? deps.isTTY : process.stdout.isTTY;
|
|
277
|
+
const latest = latestNoWait({ env: isTTY ? env : { ...env, WIZE_NO_BG_REFRESH: '1' } });
|
|
278
|
+
if (latest && semverGreater(latest, pin)) {
|
|
279
|
+
result.notice = `wize: kit ${pin} -> ${latest} available; run: npx wize-dev-kit@latest update`;
|
|
280
|
+
say(result.notice);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
if (!delegated) {
|
|
285
|
+
const via = pin && pin !== binary ? `, rendered with ${binary}` : '';
|
|
286
|
+
say(`wize: hydrated ${root} (kit_version ${pin || 'none'}${via}, ${result.adapters.length} adapters, user.toml: ${result.user_toml})`);
|
|
287
|
+
}
|
|
288
|
+
return emit();
|
|
289
|
+
} catch (err) {
|
|
290
|
+
result.ok = false;
|
|
291
|
+
const pin = result.pin;
|
|
292
|
+
warn(`wize: hydrate: ${err && err.message ? err.message : err}; run: npx --yes wize-dev-kit@${safePin(pin) || 'latest'} hydrate`);
|
|
293
|
+
result.warnings.push(`wize: hydrate: ${err && err.message ? err.message : err}`);
|
|
294
|
+
return emit();
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
module.exports = { cmdHydrate };
|
|
@@ -1,45 +1,72 @@
|
|
|
1
1
|
// `wize-dev-kit sync` — regenerate adapter outputs for the IDE targets the
|
|
2
2
|
// project opted into. Useful after editing .wize/config/project.toml,
|
|
3
3
|
// running `agent create`, or pulling kit changes that don't bump version.
|
|
4
|
+
//
|
|
5
|
+
// sync is the explicit "regenerate everything" command, so it renders
|
|
6
|
+
// unguarded. It never writes user.toml, .gitignore or kit_version. For a
|
|
7
|
+
// fresh checkout `hydrate` is the safe command; sync stays for old hook
|
|
8
|
+
// scripts and for pins that predate hydrate.
|
|
4
9
|
|
|
5
10
|
'use strict';
|
|
6
11
|
|
|
7
|
-
const
|
|
8
|
-
const
|
|
9
|
-
const {
|
|
12
|
+
const { loadProjectConfig } = require('../toml.js');
|
|
13
|
+
const { renderTargets } = require('../render-targets.js');
|
|
14
|
+
const { writeMarker } = require('../marker.js');
|
|
15
|
+
const { compareVersions, parse, safePin } = require('../semver.js');
|
|
16
|
+
const { loadInstalledKitVersion } = require('./update.js');
|
|
17
|
+
const { supportsHydrate } = require('../project-status.js');
|
|
18
|
+
|
|
19
|
+
// -> 'none' | 'project-behind' | 'project-ahead'
|
|
20
|
+
function skewOf(pin, binary) {
|
|
21
|
+
if (!pin || !binary || !parse(pin) || !parse(binary)) return 'none';
|
|
22
|
+
const cmp = compareVersions(pin, binary);
|
|
23
|
+
return cmp < 0 ? 'project-behind' : cmp > 0 ? 'project-ahead' : 'none';
|
|
24
|
+
}
|
|
10
25
|
|
|
11
26
|
function cmdSync({ kitRoot, projectRoot, opts = {} } = {}) {
|
|
12
27
|
const log = opts.log || console.log;
|
|
28
|
+
const warn = opts.warn || console.error;
|
|
13
29
|
const cfg = loadProjectConfig(projectRoot);
|
|
14
30
|
if (!cfg.project) {
|
|
15
31
|
log('No .wize/config/project.toml found here. Run `wize-dev-kit install` first.');
|
|
16
|
-
return { changed: false };
|
|
32
|
+
return { changed: false, adapters: [], skew: 'none' };
|
|
17
33
|
}
|
|
18
34
|
const ideTargets = (cfg.install && cfg.install.ide_targets) || ['claude-code', 'generic'];
|
|
19
35
|
const profiles = (cfg.install && cfg.install.profiles) || ['core'];
|
|
36
|
+
const pin = (typeof cfg.project.kit_version === 'string' && cfg.project.kit_version) || null;
|
|
37
|
+
const binary = loadInstalledKitVersion(kitRoot);
|
|
38
|
+
|
|
39
|
+
const skew = skewOf(pin, binary);
|
|
40
|
+
if (skew === 'project-behind') {
|
|
41
|
+
warn(`wize: project pinned ${pin}, running ${binary}; for an exact render run: npx --yes wize-dev-kit@${safePin(pin) || 'latest'} sync (or update the pin: npx wize-dev-kit@latest update)`);
|
|
42
|
+
} else if (skew === 'project-ahead') {
|
|
43
|
+
warn(`wize: project pinned ${pin} is newer than this kit ${binary}; run: npx --yes wize-dev-kit@${safePin(pin) || 'latest'} sync`);
|
|
44
|
+
}
|
|
45
|
+
if (supportsHydrate(pin)) warn('prefer: npx wize-dev-kit hydrate');
|
|
46
|
+
|
|
20
47
|
log(`Syncing ${ideTargets.length} adapter(s) for profile(s) ${profiles.join(' + ')}:`);
|
|
21
48
|
|
|
22
|
-
const results =
|
|
23
|
-
for (const
|
|
24
|
-
|
|
25
|
-
if (
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
results.
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
}
|
|
49
|
+
const { adapters: results } = renderTargets({ kitRoot, projectRoot, targets: ideTargets, profiles });
|
|
50
|
+
for (const a of results) {
|
|
51
|
+
if (a.skipped) log(` - ${a.code}: skipped (${a.reason === 'adapter missing' ? 'adapter missing in installed kit' : a.reason})`);
|
|
52
|
+
else if (a.error) log(` ✖ ${a.code}: ${a.error}`);
|
|
53
|
+
else log(` ✓ ${a.code}: ${a.written + a.unchanged} file(s) emitted`);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const written = results.reduce((n, a) => n + (a.written || 0), 0);
|
|
57
|
+
if (!results.some(a => a.error)) {
|
|
58
|
+
writeMarker(projectRoot, {
|
|
59
|
+
kit_version: binary,
|
|
60
|
+
targets: ideTargets,
|
|
61
|
+
profiles,
|
|
62
|
+
counts: { written, unchanged: results.reduce((n, a) => n + (a.unchanged || 0), 0), skipped_tracked: 0 },
|
|
63
|
+
delegated: false,
|
|
64
|
+
rendered_with: binary
|
|
65
|
+
});
|
|
40
66
|
}
|
|
67
|
+
|
|
41
68
|
log('\nDone. Restart your IDE if it caches skills at startup.');
|
|
42
|
-
return { changed:
|
|
69
|
+
return { changed: written > 0, adapters: results, skew };
|
|
43
70
|
}
|
|
44
71
|
|
|
45
72
|
module.exports = { cmdSync };
|