@stage5/lumine 0.1.4 → 0.1.5
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 +6 -0
- package/bin/lumine.js +152 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -49,6 +49,12 @@ Reference folders are marked `readOnly` in `.twinkle/lumine-project.json`.
|
|
|
49
49
|
Running `lumine save` from a reference folder is blocked; fork the source Build
|
|
50
50
|
first if you want an editable workspace.
|
|
51
51
|
|
|
52
|
+
The CLI checks npm for the latest `@stage5/lumine` version on normal commands.
|
|
53
|
+
If the installed copy is outdated, it prints an update warning and records the
|
|
54
|
+
version state in `.twinkle/lumine-project.json` so local agents can tell when
|
|
55
|
+
they should rerun with `npx @stage5/lumine@latest`. Use `--no-update-check` to
|
|
56
|
+
skip that advisory network check.
|
|
57
|
+
|
|
52
58
|
After pulling a project, run an agent from the pulled folder:
|
|
53
59
|
|
|
54
60
|
```bash
|
package/bin/lumine.js
CHANGED
|
@@ -8,12 +8,14 @@ import { stdin as input, stdout as output } from "process";
|
|
|
8
8
|
|
|
9
9
|
const DEFAULT_API_URL = "https://api.twinkle.network";
|
|
10
10
|
const DEFAULT_SITE_URL = "https://www.twin-kle.com";
|
|
11
|
+
const DEFAULT_NPM_REGISTRY_URL = "https://registry.npmjs.org";
|
|
11
12
|
const DEFAULT_AUTH_FILE = path.join(
|
|
12
13
|
os.homedir(),
|
|
13
14
|
".twinkle",
|
|
14
15
|
"lumine-cli-auth.json",
|
|
15
16
|
);
|
|
16
17
|
const DEFAULT_TIMEOUT_MS = 20000;
|
|
18
|
+
const UPDATE_CHECK_TIMEOUT_MS = 1500;
|
|
17
19
|
const DEFAULT_PROJECT_LIMIT = 50;
|
|
18
20
|
const PROJECT_METADATA_DIR = ".twinkle";
|
|
19
21
|
const PROJECT_METADATA_FILE = "lumine-project.json";
|
|
@@ -35,6 +37,7 @@ const BUNDLED_SDK_REFERENCE_URL = new URL(
|
|
|
35
37
|
"../sdk/BUILD_SDK_INDEX.md",
|
|
36
38
|
import.meta.url,
|
|
37
39
|
);
|
|
40
|
+
const PACKAGE_METADATA_URL = new URL("../package.json", import.meta.url);
|
|
38
41
|
const SDK_REFERENCE_FALLBACK = `${LUMINE_SDK_REFERENCE_MARKER}
|
|
39
42
|
# Twinkle Build SDK Reference
|
|
40
43
|
|
|
@@ -61,6 +64,7 @@ Lumine CLI as the source of truth for saving this workspace back to Twinkle.
|
|
|
61
64
|
|
|
62
65
|
- Read .twinkle/lumine-project.json before changing files.
|
|
63
66
|
- Treat build.canWrite, build.canPublish, and build.contributionRootBuildId as authoritative.
|
|
67
|
+
- If lumineCli.updateAvailable is true, ask the user to rerun with npx @stage5/lumine@latest before saving.
|
|
64
68
|
- Read ${SDK_REFERENCE_FILE} before adding, removing, or changing any Twinkle.* SDK calls.
|
|
65
69
|
- If build.canWrite is false, do not save changes.
|
|
66
70
|
- If build.canPublish is false or contributionRootBuildId is set, this checkout is a contribution branch. Save only to this branch and do not run lumine launch or lumine save --publish.
|
|
@@ -102,6 +106,7 @@ the workspace to save.
|
|
|
102
106
|
## Source Of Truth
|
|
103
107
|
|
|
104
108
|
- Read .twinkle/lumine-project.json before using these files.
|
|
109
|
+
- If lumineCli.updateAvailable is true, ask the user to rerun with npx @stage5/lumine@latest before borrowing patterns.
|
|
105
110
|
- If metadata.readOnly is true or build.role is "reference", do not run lumine save from this directory.
|
|
106
111
|
- To start from this Build, run lumine fork with the source build id and edit the forked workspace.
|
|
107
112
|
- Do not edit another local checkout to bypass reference read-only semantics.
|
|
@@ -132,10 +137,14 @@ main().catch((error) => {
|
|
|
132
137
|
|
|
133
138
|
async function main() {
|
|
134
139
|
const options = parseArgs(process.argv.slice(2));
|
|
140
|
+
options.lumineCli = await loadLumineCliVersionInfo({ options });
|
|
135
141
|
if (options.help) {
|
|
136
142
|
printHelp();
|
|
137
143
|
return;
|
|
138
144
|
}
|
|
145
|
+
if (options.updateCheck) {
|
|
146
|
+
await maybeCheckForLumineCliUpdate({ options });
|
|
147
|
+
}
|
|
139
148
|
|
|
140
149
|
if (options.command === "workspace") {
|
|
141
150
|
await workspace(options);
|
|
@@ -1117,6 +1126,7 @@ async function writeProjectMetadata({
|
|
|
1117
1126
|
: null,
|
|
1118
1127
|
apiUrl: options.apiUrl,
|
|
1119
1128
|
siteUrl: options.siteUrl,
|
|
1129
|
+
lumineCli: serializeLumineCliMetadata(options),
|
|
1120
1130
|
manifest,
|
|
1121
1131
|
pulledAt,
|
|
1122
1132
|
lastSavedAt,
|
|
@@ -1164,6 +1174,7 @@ async function writeReferenceMetadata({
|
|
|
1164
1174
|
},
|
|
1165
1175
|
apiUrl: options.apiUrl,
|
|
1166
1176
|
siteUrl: options.siteUrl,
|
|
1177
|
+
lumineCli: serializeLumineCliMetadata(options),
|
|
1167
1178
|
manifest,
|
|
1168
1179
|
pulledAt,
|
|
1169
1180
|
},
|
|
@@ -1258,6 +1269,20 @@ async function saveSelectedBuild({ options, auth, build }) {
|
|
|
1258
1269
|
});
|
|
1259
1270
|
}
|
|
1260
1271
|
|
|
1272
|
+
function serializeLumineCliMetadata(options) {
|
|
1273
|
+
const info = options.lumineCli || {};
|
|
1274
|
+
return {
|
|
1275
|
+
packageName: info.packageName || "@stage5/lumine",
|
|
1276
|
+
version: info.version || null,
|
|
1277
|
+
latestVersion: info.latestVersion || null,
|
|
1278
|
+
updateAvailable: Boolean(info.updateAvailable),
|
|
1279
|
+
updateCommand: info.updateCommand || "npx @stage5/lumine@latest",
|
|
1280
|
+
checkedAt: info.checkedAt || null,
|
|
1281
|
+
checkFailed: Boolean(info.checkFailed),
|
|
1282
|
+
checkSkipped: Boolean(info.checkSkipped),
|
|
1283
|
+
};
|
|
1284
|
+
}
|
|
1285
|
+
|
|
1261
1286
|
function printBuildList(builds) {
|
|
1262
1287
|
if (!builds.length) {
|
|
1263
1288
|
console.log("No owned or team Twinkle builds found.");
|
|
@@ -1503,6 +1528,117 @@ async function request({ method = "GET", url, authToken, body, timeoutMs }) {
|
|
|
1503
1528
|
}
|
|
1504
1529
|
}
|
|
1505
1530
|
|
|
1531
|
+
async function loadLumineCliVersionInfo({ options }) {
|
|
1532
|
+
const packageMetadata = await loadLocalPackageMetadata();
|
|
1533
|
+
const packageName = packageMetadata.name || "@stage5/lumine";
|
|
1534
|
+
const version = packageMetadata.version || null;
|
|
1535
|
+
return {
|
|
1536
|
+
packageName,
|
|
1537
|
+
version,
|
|
1538
|
+
latestVersion: null,
|
|
1539
|
+
updateAvailable: false,
|
|
1540
|
+
updateCommand: `npx ${packageName}@latest`,
|
|
1541
|
+
checkedAt: null,
|
|
1542
|
+
checkFailed: false,
|
|
1543
|
+
checkSkipped: !options.updateCheck,
|
|
1544
|
+
};
|
|
1545
|
+
}
|
|
1546
|
+
|
|
1547
|
+
async function loadLocalPackageMetadata() {
|
|
1548
|
+
try {
|
|
1549
|
+
const rawPackage = await fs.readFile(PACKAGE_METADATA_URL, "utf8");
|
|
1550
|
+
const parsedPackage = JSON.parse(rawPackage);
|
|
1551
|
+
return {
|
|
1552
|
+
name: String(parsedPackage?.name || "").trim(),
|
|
1553
|
+
version: String(parsedPackage?.version || "").trim(),
|
|
1554
|
+
};
|
|
1555
|
+
} catch {
|
|
1556
|
+
return {
|
|
1557
|
+
name: "@stage5/lumine",
|
|
1558
|
+
version: null,
|
|
1559
|
+
};
|
|
1560
|
+
}
|
|
1561
|
+
}
|
|
1562
|
+
|
|
1563
|
+
async function maybeCheckForLumineCliUpdate({ options }) {
|
|
1564
|
+
const info = options.lumineCli || (await loadLumineCliVersionInfo({ options }));
|
|
1565
|
+
const checkedAt = new Date().toISOString();
|
|
1566
|
+
if (!info.packageName || !info.version) {
|
|
1567
|
+
options.lumineCli = {
|
|
1568
|
+
...info,
|
|
1569
|
+
checkedAt,
|
|
1570
|
+
checkFailed: true,
|
|
1571
|
+
checkSkipped: false,
|
|
1572
|
+
};
|
|
1573
|
+
return;
|
|
1574
|
+
}
|
|
1575
|
+
|
|
1576
|
+
try {
|
|
1577
|
+
const latestVersion = await loadLatestPackageVersion({
|
|
1578
|
+
packageName: info.packageName,
|
|
1579
|
+
registryUrl: options.npmRegistryUrl,
|
|
1580
|
+
});
|
|
1581
|
+
const updateAvailable = isNewerVersion(latestVersion, info.version);
|
|
1582
|
+
options.lumineCli = {
|
|
1583
|
+
...info,
|
|
1584
|
+
latestVersion,
|
|
1585
|
+
updateAvailable,
|
|
1586
|
+
checkedAt,
|
|
1587
|
+
checkFailed: false,
|
|
1588
|
+
checkSkipped: false,
|
|
1589
|
+
};
|
|
1590
|
+
if (updateAvailable) {
|
|
1591
|
+
printLumineCliUpdateWarning(options.lumineCli);
|
|
1592
|
+
}
|
|
1593
|
+
} catch {
|
|
1594
|
+
options.lumineCli = {
|
|
1595
|
+
...info,
|
|
1596
|
+
checkedAt,
|
|
1597
|
+
checkFailed: true,
|
|
1598
|
+
checkSkipped: false,
|
|
1599
|
+
};
|
|
1600
|
+
}
|
|
1601
|
+
}
|
|
1602
|
+
|
|
1603
|
+
async function loadLatestPackageVersion({ packageName, registryUrl }) {
|
|
1604
|
+
const encodedPackageName = encodeURIComponent(packageName);
|
|
1605
|
+
const result = await requestJson({
|
|
1606
|
+
url: `${registryUrl}/${encodedPackageName}/latest`,
|
|
1607
|
+
timeoutMs: UPDATE_CHECK_TIMEOUT_MS,
|
|
1608
|
+
});
|
|
1609
|
+
const latestVersion = String(result?.version || "").trim();
|
|
1610
|
+
if (!latestVersion) {
|
|
1611
|
+
throw new Error("No latest package version returned");
|
|
1612
|
+
}
|
|
1613
|
+
return latestVersion;
|
|
1614
|
+
}
|
|
1615
|
+
|
|
1616
|
+
function isNewerVersion(latestVersion, currentVersion) {
|
|
1617
|
+
const latestParts = parseSemverParts(latestVersion);
|
|
1618
|
+
const currentParts = parseSemverParts(currentVersion);
|
|
1619
|
+
if (!latestParts || !currentParts) return false;
|
|
1620
|
+
for (let index = 0; index < 3; index += 1) {
|
|
1621
|
+
if (latestParts[index] > currentParts[index]) return true;
|
|
1622
|
+
if (latestParts[index] < currentParts[index]) return false;
|
|
1623
|
+
}
|
|
1624
|
+
return false;
|
|
1625
|
+
}
|
|
1626
|
+
|
|
1627
|
+
function parseSemverParts(value) {
|
|
1628
|
+
const match = String(value || "")
|
|
1629
|
+
.trim()
|
|
1630
|
+
.match(/^v?(\d+)\.(\d+)\.(\d+)/);
|
|
1631
|
+
if (!match) return null;
|
|
1632
|
+
return [Number(match[1]), Number(match[2]), Number(match[3])];
|
|
1633
|
+
}
|
|
1634
|
+
|
|
1635
|
+
function printLumineCliUpdateWarning(info) {
|
|
1636
|
+
console.error(
|
|
1637
|
+
`lumine: update available for ${info.packageName}: ${info.version} -> ${info.latestVersion}.`,
|
|
1638
|
+
);
|
|
1639
|
+
console.error(`lumine: run \`${info.updateCommand}\` to use the latest CLI.`);
|
|
1640
|
+
}
|
|
1641
|
+
|
|
1506
1642
|
function parseArgs(args) {
|
|
1507
1643
|
const firstArg = args[0] || "";
|
|
1508
1644
|
const firstArgIsCommand =
|
|
@@ -1517,7 +1653,13 @@ function parseArgs(args) {
|
|
|
1517
1653
|
const rest = command === "workspace" ? args : args.slice(1);
|
|
1518
1654
|
const raw = {};
|
|
1519
1655
|
const positional = [];
|
|
1520
|
-
const booleanFlags = new Set([
|
|
1656
|
+
const booleanFlags = new Set([
|
|
1657
|
+
"noOpen",
|
|
1658
|
+
"open",
|
|
1659
|
+
"publish",
|
|
1660
|
+
"save",
|
|
1661
|
+
"noUpdateCheck",
|
|
1662
|
+
]);
|
|
1521
1663
|
|
|
1522
1664
|
for (let i = 0; i < rest.length; i += 1) {
|
|
1523
1665
|
const arg = rest[i];
|
|
@@ -1557,6 +1699,13 @@ function parseArgs(args) {
|
|
|
1557
1699
|
siteUrl: trimTrailingSlash(
|
|
1558
1700
|
String(raw.siteUrl || process.env.TWINKLE_SITE_URL || DEFAULT_SITE_URL),
|
|
1559
1701
|
),
|
|
1702
|
+
npmRegistryUrl: trimTrailingSlash(
|
|
1703
|
+
String(
|
|
1704
|
+
raw.npmRegistryUrl ||
|
|
1705
|
+
process.env.LUMINE_NPM_REGISTRY_URL ||
|
|
1706
|
+
DEFAULT_NPM_REGISTRY_URL,
|
|
1707
|
+
),
|
|
1708
|
+
),
|
|
1560
1709
|
authFile: String(
|
|
1561
1710
|
raw.authFile || process.env.TWINKLE_CLI_AUTH_FILE || DEFAULT_AUTH_FILE,
|
|
1562
1711
|
),
|
|
@@ -1579,6 +1728,7 @@ function parseArgs(args) {
|
|
|
1579
1728
|
openBrowser: parseBoolean(raw.noOpen, false)
|
|
1580
1729
|
? false
|
|
1581
1730
|
: parseBoolean(raw.open, true),
|
|
1731
|
+
updateCheck: parseBoolean(raw.noUpdateCheck, false) ? false : true,
|
|
1582
1732
|
timeoutMs: Math.max(
|
|
1583
1733
|
Number(raw.timeoutMs || process.env.TWINKLE_TIMEOUT_MS) ||
|
|
1584
1734
|
DEFAULT_TIMEOUT_MS,
|
|
@@ -1802,6 +1952,7 @@ Options:
|
|
|
1802
1952
|
--publish Publish after saving
|
|
1803
1953
|
--save Save local files before launch
|
|
1804
1954
|
--limit <number> Number of projects to show
|
|
1955
|
+
--no-update-check Skip the npm latest-version check
|
|
1805
1956
|
--no-open Print the approval URL without opening a browser
|
|
1806
1957
|
`);
|
|
1807
1958
|
}
|