loopengine 0.1.13 → 0.1.14
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/dist/bin/package-manager.d.ts +16 -8
- package/dist/bin/package-manager.js +46 -10
- package/package.json +1 -1
|
@@ -29,6 +29,14 @@ export interface PackageManifest {
|
|
|
29
29
|
* same role .create-loopengine.json already plays for template files. */
|
|
30
30
|
export interface InstalledPackageRecord {
|
|
31
31
|
version: string;
|
|
32
|
+
/** The exact spec (bare registry name, "name@version", a git+ssh/
|
|
33
|
+
* git+https URL with a #committish, a file: path, ...) last used to
|
|
34
|
+
* successfully install or upgrade this package — see
|
|
35
|
+
* oldContentSpec's own doc comment for why upgradePackage needs this
|
|
36
|
+
* stored verbatim rather than reconstructed from `packageName`.
|
|
37
|
+
* Optional only because a package installed before this field existed
|
|
38
|
+
* has no recorded value — see oldContentSpec's own fallback. */
|
|
39
|
+
spec?: string;
|
|
32
40
|
tools: string[];
|
|
33
41
|
skills: string[];
|
|
34
42
|
actauthRules: string[];
|
|
@@ -99,14 +107,14 @@ export interface UpgradeFileResult {
|
|
|
99
107
|
* to `packageName`, i.e. "latest") currently resolves to. Tool and skill
|
|
100
108
|
* files get a real three-way merge (mine = current file, possibly
|
|
101
109
|
* hand-edited since install; base = the version recorded at
|
|
102
|
-
* install/last-upgrade, refetched via
|
|
103
|
-
*
|
|
104
|
-
*
|
|
105
|
-
*
|
|
106
|
-
*
|
|
107
|
-
*
|
|
108
|
-
*
|
|
109
|
-
*
|
|
110
|
+
* install/last-upgrade, refetched via oldContentSpec; theirs = newly
|
|
111
|
+
* fetched) — identical technique to `create-loopengine upgrade`, just
|
|
112
|
+
* applied to package-managed files instead of template files. actauth
|
|
113
|
+
* rules upgrade per-rule instead: the target actauth.yml holds rules
|
|
114
|
+
* from other packages and hand-written ones too, so there's no coherent
|
|
115
|
+
* "whole file" base/theirs to merge — a rule unchanged since install
|
|
116
|
+
* updates cleanly; a hand-edited one is left alone and reported as a
|
|
117
|
+
* conflict rather than overwritten. */
|
|
110
118
|
export declare function upgradePackage(agentName: string, packageName: string, options?: FetchOptions & {
|
|
111
119
|
spec?: string;
|
|
112
120
|
}): Promise<{
|
|
@@ -283,6 +283,7 @@ export async function installPackage(agentName, spec, options = {}) {
|
|
|
283
283
|
}
|
|
284
284
|
provenance[manifest.name] = {
|
|
285
285
|
version: manifest.version,
|
|
286
|
+
spec,
|
|
286
287
|
tools: toolNames,
|
|
287
288
|
skills: skillIds,
|
|
288
289
|
actauthRules: rules.map((r) => r.name),
|
|
@@ -321,18 +322,53 @@ function mergeFile(mine, base, theirs) {
|
|
|
321
322
|
rmSync(scratchDir, { recursive: true, force: true });
|
|
322
323
|
return { merged, conflicted };
|
|
323
324
|
}
|
|
325
|
+
// A git+ssh/git+https/git: URL, a plain https: tarball URL, or a local
|
|
326
|
+
// file:/relative/absolute path all already pin to exact, immutable
|
|
327
|
+
// content on their own (a #committish, or the file/tarball's own
|
|
328
|
+
// content) — appending "@version" to one of these doesn't select an
|
|
329
|
+
// older version the way it does for a registry specifier, it corrupts
|
|
330
|
+
// the spec. Confirmed live: `npm pack 'git+file://...#v1.0.0@1.0.0'`
|
|
331
|
+
// fails outright ("The git reference could not be found... pathspec
|
|
332
|
+
// 'v1.0.0@1.0.0'"), it doesn't fall back to resolving just the tag.
|
|
333
|
+
const PINNED_SPEC = /^(git\+|git:|https?:|file:|\.\.?\/|\/)/;
|
|
334
|
+
/** What to fetch to reconstruct the exact content that was installed or
|
|
335
|
+
* last upgraded to, for use as the three-way merge's `base` — as
|
|
336
|
+
* distinct from `spec`, which is what the *new* content resolves to.
|
|
337
|
+
* A plain registry specifier (bare or scoped name, with or without its
|
|
338
|
+
* own "@version") is repinned to `version` — the manifest's own
|
|
339
|
+
* declared version at that install/upgrade, which is what actually got
|
|
340
|
+
* written to disk, regardless of whether the range originally given
|
|
341
|
+
* would still resolve there today. A git/file/URL spec is returned
|
|
342
|
+
* as-is — see PINNED_SPEC's own doc comment for why appending "@version"
|
|
343
|
+
* to one of those breaks instead of pinning. `recordedSpec` is only
|
|
344
|
+
* absent for a package installed before InstalledPackageRecord.spec
|
|
345
|
+
* existed; falling back to `packageName` there reproduces this
|
|
346
|
+
* function's own old (buggy for a git/file install) behavior exactly —
|
|
347
|
+
* no worse than before, and only for a package that hasn't upgraded
|
|
348
|
+
* since. */
|
|
349
|
+
function oldContentSpec(recordedSpec, packageName, version) {
|
|
350
|
+
const base = recordedSpec ?? packageName;
|
|
351
|
+
if (PINNED_SPEC.test(base))
|
|
352
|
+
return base;
|
|
353
|
+
// Strip any version/tag the spec already carries (a scoped name's own
|
|
354
|
+
// leading '@' isn't this — only a second '@' after the name is) before
|
|
355
|
+
// repinning, so re-upgrading an already-version-pinned install doesn't
|
|
356
|
+
// produce a doubled-up "name@1.0.0@1.0.0".
|
|
357
|
+
const bareName = base.startsWith('@') ? `@${base.slice(1).split('@')[0]}` : base.split('@')[0];
|
|
358
|
+
return `${bareName}@${version}`;
|
|
359
|
+
}
|
|
324
360
|
/** Upgrades an already-installed package to whatever `spec` (defaulting
|
|
325
361
|
* to `packageName`, i.e. "latest") currently resolves to. Tool and skill
|
|
326
362
|
* files get a real three-way merge (mine = current file, possibly
|
|
327
363
|
* hand-edited since install; base = the version recorded at
|
|
328
|
-
* install/last-upgrade, refetched via
|
|
329
|
-
*
|
|
330
|
-
*
|
|
331
|
-
*
|
|
332
|
-
*
|
|
333
|
-
*
|
|
334
|
-
*
|
|
335
|
-
*
|
|
364
|
+
* install/last-upgrade, refetched via oldContentSpec; theirs = newly
|
|
365
|
+
* fetched) — identical technique to `create-loopengine upgrade`, just
|
|
366
|
+
* applied to package-managed files instead of template files. actauth
|
|
367
|
+
* rules upgrade per-rule instead: the target actauth.yml holds rules
|
|
368
|
+
* from other packages and hand-written ones too, so there's no coherent
|
|
369
|
+
* "whole file" base/theirs to merge — a rule unchanged since install
|
|
370
|
+
* updates cleanly; a hand-edited one is left alone and reported as a
|
|
371
|
+
* conflict rather than overwritten. */
|
|
336
372
|
export async function upgradePackage(agentName, packageName, options = {}) {
|
|
337
373
|
const fetch = options.fetchPackageDir ?? fetchPackageDir;
|
|
338
374
|
const provenance = readProvenance(agentName);
|
|
@@ -341,7 +377,7 @@ export async function upgradePackage(agentName, packageName, options = {}) {
|
|
|
341
377
|
throw new PackageNotInstalledError(`Package '${packageName}' isn't installed for '${agentName}'.`);
|
|
342
378
|
}
|
|
343
379
|
const spec = options.spec ?? packageName;
|
|
344
|
-
const oldDir = fetch(
|
|
380
|
+
const oldDir = fetch(oldContentSpec(record.spec, packageName, record.version));
|
|
345
381
|
const newDir = fetch(spec);
|
|
346
382
|
const oldManifest = readManifest(oldDir);
|
|
347
383
|
const newManifest = readManifest(newDir);
|
|
@@ -416,7 +452,7 @@ export async function upgradePackage(agentName, packageName, options = {}) {
|
|
|
416
452
|
updateActauthRule(agentName, ruleName, { scope: newRule.scope, tool: newRule.tool, decision: newRule.decision });
|
|
417
453
|
results.push({ path, status: 'updated' });
|
|
418
454
|
}
|
|
419
|
-
provenance[packageName] = { ...record, version: newManifest.version, contentHashes: newContentHashes, env: newManifest.env ?? record.env };
|
|
455
|
+
provenance[packageName] = { ...record, version: newManifest.version, spec, contentHashes: newContentHashes, env: newManifest.env ?? record.env };
|
|
420
456
|
writeProvenance(agentName, provenance);
|
|
421
457
|
return { files: results };
|
|
422
458
|
}
|