create-loopengine 0.1.15 → 0.1.16
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/README.md +11 -4
- package/dist/cli.d.ts +26 -0
- package/dist/cli.js +81 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -115,10 +115,17 @@ Each of the five template-owned files gets one of:
|
|
|
115
115
|
as any git merge conflict — resolve them by hand, then `npx tsc
|
|
116
116
|
--noEmit` to confirm it builds.
|
|
117
117
|
|
|
118
|
-
`upgrade`
|
|
119
|
-
`package.json`
|
|
120
|
-
|
|
121
|
-
|
|
118
|
+
`upgrade` also bumps whichever of `loopengine`/`actauth`/`skillgarden`
|
|
119
|
+
are already in your `package.json` to their latest published version
|
|
120
|
+
(never adds one you don't already depend on) and runs `npm install` for
|
|
121
|
+
you — a merged file that now calls a newer export is a silent, hard-to-
|
|
122
|
+
notice failure if the installed package hasn't actually caught up, so
|
|
123
|
+
this isn't left as a manual step. If the install itself fails (offline,
|
|
124
|
+
a registry hiccup), the version bump is still written to `package.json`;
|
|
125
|
+
just run `npm install` yourself to finish.
|
|
126
|
+
|
|
127
|
+
`upgrade` never touches `agents/`, `README.md`, `.env.example`, or any
|
|
128
|
+
dependency *other* than those three.
|
|
122
129
|
|
|
123
130
|
## Running in production
|
|
124
131
|
|
package/dist/cli.d.ts
CHANGED
|
@@ -11,10 +11,29 @@ export interface UpgradeFileResult {
|
|
|
11
11
|
file: string;
|
|
12
12
|
status: UpgradeFileStatus;
|
|
13
13
|
}
|
|
14
|
+
export interface UpgradeDependencyResult {
|
|
15
|
+
name: string;
|
|
16
|
+
from: string;
|
|
17
|
+
to: string;
|
|
18
|
+
}
|
|
14
19
|
export interface UpgradeResult {
|
|
15
20
|
fromVersion: string;
|
|
16
21
|
toVersion: string;
|
|
17
22
|
files: UpgradeFileResult[];
|
|
23
|
+
/** Which of loopengine/actauth/skillgarden actually had their
|
|
24
|
+
* package.json range bumped — only ones already present as a
|
|
25
|
+
* dependency, never newly added (see bumpDependencies's own doc
|
|
26
|
+
* comment). Empty if the project has no package.json, or every present
|
|
27
|
+
* one was already at the latest range. */
|
|
28
|
+
dependencies: UpgradeDependencyResult[];
|
|
29
|
+
/** Only attempted when `dependencies` is non-empty — running `npm
|
|
30
|
+
* install` for a project with nothing to bump would be pointless. */
|
|
31
|
+
npmInstall?: {
|
|
32
|
+
ok: true;
|
|
33
|
+
} | {
|
|
34
|
+
ok: false;
|
|
35
|
+
error: string;
|
|
36
|
+
};
|
|
18
37
|
}
|
|
19
38
|
export interface UpgradeOptions {
|
|
20
39
|
/** Defaults to process.cwd(). */
|
|
@@ -31,6 +50,13 @@ export interface UpgradeOptions {
|
|
|
31
50
|
* (a real `npm pack`). Test-only seam to avoid hitting the real
|
|
32
51
|
* registry for a fixture "old" template. */
|
|
33
52
|
resolveBaseTemplateDir?: (version: string) => string;
|
|
53
|
+
/** Resolves a package's current latest version — defaults to a real
|
|
54
|
+
* `npm view <pkg> version`. Test-only seam to avoid hitting the real
|
|
55
|
+
* registry. */
|
|
56
|
+
resolveLatestVersion?: (pkg: string) => string;
|
|
57
|
+
/** Runs `npm install` in projectDir — defaults to a real one. Test-only
|
|
58
|
+
* seam to avoid actually installing anything during tests. */
|
|
59
|
+
runNpmInstall?: (projectDir: string) => void;
|
|
34
60
|
}
|
|
35
61
|
export declare function upgradeProject(options?: UpgradeOptions): UpgradeResult;
|
|
36
62
|
export declare function main(argv?: string[]): void;
|
package/dist/cli.js
CHANGED
|
@@ -163,8 +163,76 @@ export function upgradeProject(options = {}) {
|
|
|
163
163
|
const resolveBase = options.resolveBaseTemplateDir ?? fetchPublishedTemplateDir;
|
|
164
164
|
const baseTemplateDir = resolveBase(fromVersion);
|
|
165
165
|
const files = UPGRADE_CANDIDATE_FILES.map((candidate) => upgradeFile(candidate, baseTemplateDir, currentTemplateDir, projectDir));
|
|
166
|
+
const resolveLatestVersion = options.resolveLatestVersion ?? resolveLatestVersionFromNpm;
|
|
167
|
+
const dependencies = bumpDependencies(projectDir, resolveLatestVersion);
|
|
168
|
+
let npmInstall;
|
|
169
|
+
if (dependencies.length > 0) {
|
|
170
|
+
const install = options.runNpmInstall ?? runRealNpmInstall;
|
|
171
|
+
try {
|
|
172
|
+
install(projectDir);
|
|
173
|
+
npmInstall = { ok: true };
|
|
174
|
+
}
|
|
175
|
+
catch (err) {
|
|
176
|
+
// Non-fatal — the file merge and the package.json bump already
|
|
177
|
+
// succeeded and are on disk either way; a failed install (offline,
|
|
178
|
+
// a registry hiccup) just means the operator runs `npm install`
|
|
179
|
+
// themselves, the same single command this was trying to save them
|
|
180
|
+
// from typing, not a reason to unwind everything already done.
|
|
181
|
+
npmInstall = { ok: false, error: err instanceof Error ? err.message : String(err) };
|
|
182
|
+
}
|
|
183
|
+
}
|
|
166
184
|
writeFileSync(provenancePath, JSON.stringify({ version: toVersion }, null, 2) + '\n');
|
|
167
|
-
return { fromVersion, toVersion, files };
|
|
185
|
+
return { fromVersion, toVersion, files, dependencies, npmInstall };
|
|
186
|
+
}
|
|
187
|
+
function resolveLatestVersionFromNpm(pkg) {
|
|
188
|
+
return execFileSync('npm', ['view', pkg, 'version'], { stdio: 'pipe' }).toString().trim();
|
|
189
|
+
}
|
|
190
|
+
function runRealNpmInstall(projectDir) {
|
|
191
|
+
execFileSync('npm', ['install'], { cwd: projectDir, stdio: 'pipe' });
|
|
192
|
+
}
|
|
193
|
+
// Only loopengine/actauth/skillgarden — the three packages a scaffolded
|
|
194
|
+
// project's own adapters/http.ts can import directly (see this repo's own
|
|
195
|
+
// README on why: template code that imports a package must declare it as
|
|
196
|
+
// its own direct dependency, not rely on loopengine's transitive one) —
|
|
197
|
+
// and only ones already present in the project's own package.json.
|
|
198
|
+
// Deliberately never *adds* a dependency a project doesn't already have:
|
|
199
|
+
// this command upgrades what's there, it doesn't decide what a project
|
|
200
|
+
// should depend on.
|
|
201
|
+
const UPGRADABLE_DEPENDENCIES = ['loopengine', 'actauth', 'skillgarden'];
|
|
202
|
+
/** Bumps package.json's dependency ranges for whichever of
|
|
203
|
+
* loopengine/actauth/skillgarden are already present, to `^<latest>` —
|
|
204
|
+
* run automatically as part of `upgrade` (not left as a manual follow-up
|
|
205
|
+
* step) because a project whose merged template code now calls a newer
|
|
206
|
+
* export, but whose installed package is still old, fails silently: no
|
|
207
|
+
* conflict marker, no build error, just a feature that's quietly not
|
|
208
|
+
* there yet (confirmed live — this exact gap is what prompted adding this
|
|
209
|
+
* function in the first place, see this repo's own git history). Returns
|
|
210
|
+
* [] untouched if the project has no package.json at all, same
|
|
211
|
+
* "can't merge what isn't there" reasoning upgradeFile's own missing-file
|
|
212
|
+
* check uses. */
|
|
213
|
+
function bumpDependencies(projectDir, resolveLatestVersion) {
|
|
214
|
+
const pkgPath = join(projectDir, 'package.json');
|
|
215
|
+
if (!existsSync(pkgPath))
|
|
216
|
+
return [];
|
|
217
|
+
const pkg = JSON.parse(readFileSync(pkgPath, 'utf8'));
|
|
218
|
+
const deps = pkg.dependencies;
|
|
219
|
+
if (!deps)
|
|
220
|
+
return [];
|
|
221
|
+
const changes = [];
|
|
222
|
+
for (const name of UPGRADABLE_DEPENDENCIES) {
|
|
223
|
+
const currentRange = deps[name];
|
|
224
|
+
if (currentRange === undefined)
|
|
225
|
+
continue;
|
|
226
|
+
const latest = resolveLatestVersion(name);
|
|
227
|
+
const newRange = `^${latest}`;
|
|
228
|
+
if (currentRange === newRange)
|
|
229
|
+
continue;
|
|
230
|
+
deps[name] = newRange;
|
|
231
|
+
changes.push({ name, from: currentRange, to: newRange });
|
|
232
|
+
}
|
|
233
|
+
if (changes.length > 0)
|
|
234
|
+
writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + '\n');
|
|
235
|
+
return changes;
|
|
168
236
|
}
|
|
169
237
|
function parseUpgradeArgs(argv) {
|
|
170
238
|
let from;
|
|
@@ -187,7 +255,18 @@ function printUpgradeSummary(result) {
|
|
|
187
255
|
console.log(`${conflicted.length} file(s) have <<<<<<< conflict markers to resolve by hand before this will build.`);
|
|
188
256
|
}
|
|
189
257
|
else {
|
|
190
|
-
console.log('No conflicts.
|
|
258
|
+
console.log('No conflicts.');
|
|
259
|
+
}
|
|
260
|
+
if (result.dependencies.length > 0) {
|
|
261
|
+
console.log();
|
|
262
|
+
for (const dep of result.dependencies)
|
|
263
|
+
console.log(` ${dep.name}: ${dep.from} -> ${dep.to}`);
|
|
264
|
+
if (result.npmInstall?.ok) {
|
|
265
|
+
console.log('npm install completed.');
|
|
266
|
+
}
|
|
267
|
+
else if (result.npmInstall) {
|
|
268
|
+
console.log(`npm install failed (${result.npmInstall.error}) — run it yourself to finish picking up the new versions.`);
|
|
269
|
+
}
|
|
191
270
|
}
|
|
192
271
|
}
|
|
193
272
|
function parseArgs(argv) {
|
package/package.json
CHANGED