@zoahhq/cli 0.1.8 → 0.1.9
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 +25 -3
- package/dist/cli.mjs +366 -151
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -46,7 +46,7 @@ zoah login --organization acme # skip the organization list
|
|
|
46
46
|
|
|
47
47
|
After you sign in, the CLI asks which organization to work in. Your active organization in the web app is first and selected. Use the arrow keys to choose another, then press Enter. An account with one organization skips the question.
|
|
48
48
|
|
|
49
|
-
The CLI keeps this choice. Changing organizations in the web app does not change it. New projects from `zoah import` go into this organization
|
|
49
|
+
The CLI keeps this choice. Changing organizations in the web app does not change it. New projects from `zoah import` go into this organization, and so do directories that are imported but not swapped yet. A swapped directory stays on its project (see [Where a directory stands](#where-a-directory-stands)).
|
|
50
50
|
|
|
51
51
|
The CLI uses `ZOAH_BASE_URL` when it is set. Otherwise, it uses `https://zoah.com`. `OPACITY_BASE_URL` remains a compatibility fallback.
|
|
52
52
|
|
|
@@ -59,6 +59,14 @@ By default, this removes the **active** credentials. It removes project-local cr
|
|
|
59
59
|
|
|
60
60
|
To clear both, run logout twice.
|
|
61
61
|
|
|
62
|
+
### `zoah status`
|
|
63
|
+
|
|
64
|
+
Prints who is signed in, the CLI's organization, and this directory's project, package and state, plus what the next `zoah import` will do. It reads local files only.
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
zoah status
|
|
68
|
+
```
|
|
69
|
+
|
|
62
70
|
### `zoah whoami`
|
|
63
71
|
|
|
64
72
|
Prints the active user, the source credentials file, the base URL, and the organization the CLI works in. Use this when project credentials hide the global token.
|
|
@@ -215,18 +223,32 @@ zoah import # scans ./src
|
|
|
215
223
|
zoah import src/components # scope to a subdirectory
|
|
216
224
|
zoah import --swap # also rewrite local imports after publish
|
|
217
225
|
zoah import --project-name my-ui # override the first project name
|
|
226
|
+
zoah import --new-project # start over in a new project (before a swap)
|
|
218
227
|
zoah import --branch main # target a specific branch
|
|
219
228
|
zoah import --debug # also write .zoah/debug/payload.json
|
|
220
229
|
zoah import --print-issues warn # print issue details at or above this level
|
|
221
230
|
zoah import --dry-run # preview locally without an API call
|
|
222
231
|
```
|
|
223
232
|
|
|
224
|
-
The first import creates a project and saves its IDs to `.zoah/config.json`.
|
|
233
|
+
The first import creates a project and saves its IDs to `.zoah/config.json`. Before it scans, `zoah import` says where the directory stands and where this import goes.
|
|
234
|
+
|
|
235
|
+
#### Where a directory stands
|
|
236
|
+
|
|
237
|
+
`zoah status` prints this without scanning or calling the API.
|
|
238
|
+
|
|
239
|
+
| State | What it means | What `zoah import` does |
|
|
240
|
+
| -------- | ------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
241
|
+
| New | No `.zoah/config.json`. | Creates a project in the CLI's organization. |
|
|
242
|
+
| Imported | Linked to a project, but no source file uses its package yet. | Updates the linked project. If the CLI's organization is different, it creates a project there and relinks the directory. `--new-project` also starts a new project. |
|
|
243
|
+
| Swapped | `zoah swap` rewrote component files to use the package. | Adds and updates components in the linked project, whichever organization the CLI is in. Swapped components are already in Zoah, so the scan skips them. `--new-project` is refused, because the code depends on the package. |
|
|
244
|
+
|
|
245
|
+
A swapped directory stays on its project because its code imports that project's package. It still takes new components: add one and run `zoah import --swap`.
|
|
225
246
|
|
|
226
247
|
Notable flags:
|
|
227
248
|
|
|
228
249
|
- `--swap`: runs `zoah swap` after a successful import.
|
|
229
|
-
- `--project-name <name>`: sets the
|
|
250
|
+
- `--project-name <name>`: sets the name of a new project. Later imports use the project ID in `.zoah/config.json`.
|
|
251
|
+
- `--new-project`: creates a new project in the CLI's organization and relinks the directory. Not possible once the directory is swapped.
|
|
230
252
|
- `--branch <name>`: defaults to the project's saved branch (usually `main`).
|
|
231
253
|
- `--base-url <url>`: overrides the URL saved at login.
|
|
232
254
|
- `--print-issues <level>`: also prints full details for every issue at or above `info | warn | error`.
|
package/dist/cli.mjs
CHANGED
|
@@ -422,6 +422,7 @@ var init_client = __esm({
|
|
|
422
422
|
// src/config/local.ts
|
|
423
423
|
var local_exports = {};
|
|
424
424
|
__export(local_exports, {
|
|
425
|
+
manifestSourceFile: () => manifestSourceFile,
|
|
425
426
|
readComponentsManifest: () => readComponentsManifest,
|
|
426
427
|
readPackageManifest: () => readPackageManifest,
|
|
427
428
|
readProjectConfig: () => readProjectConfig,
|
|
@@ -430,6 +431,11 @@ __export(local_exports, {
|
|
|
430
431
|
writePackageManifest: () => writePackageManifest,
|
|
431
432
|
writeProjectConfig: () => writeProjectConfig
|
|
432
433
|
});
|
|
434
|
+
function manifestSourceFile(key, entry) {
|
|
435
|
+
if (entry.sourceFile !== void 0) return entry.sourceFile;
|
|
436
|
+
const hash = key.indexOf("#");
|
|
437
|
+
return hash === -1 ? key : key.slice(0, hash);
|
|
438
|
+
}
|
|
433
439
|
function readProjectConfig(cwd) {
|
|
434
440
|
return readCurrentOrLegacy(
|
|
435
441
|
zoahPaths.config(cwd),
|
|
@@ -471,6 +477,120 @@ var init_local = __esm({
|
|
|
471
477
|
}
|
|
472
478
|
});
|
|
473
479
|
|
|
480
|
+
// src/config/directory-state.ts
|
|
481
|
+
import { existsSync } from "fs";
|
|
482
|
+
import { readFile as readFile2 } from "fs/promises";
|
|
483
|
+
import { isAbsolute, join as join2 } from "path";
|
|
484
|
+
function importsPackage(source, packageName) {
|
|
485
|
+
const escaped = packageName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
486
|
+
return new RegExp(`from\\s+["']${escaped}(?:/[^"']*)?["']`).test(source);
|
|
487
|
+
}
|
|
488
|
+
async function readDirectoryState(cwd) {
|
|
489
|
+
const config = await readProjectConfig(cwd);
|
|
490
|
+
if (!config) return { kind: "new" };
|
|
491
|
+
const manifest = await readPackageManifest(cwd);
|
|
492
|
+
const components2 = await readComponentsManifest(cwd);
|
|
493
|
+
if (!manifest || !components2) {
|
|
494
|
+
return { kind: "imported", config, manifest, components: components2 };
|
|
495
|
+
}
|
|
496
|
+
const files = new Set(
|
|
497
|
+
Object.entries(components2).map(
|
|
498
|
+
([key, entry]) => manifestSourceFile(key, entry)
|
|
499
|
+
)
|
|
500
|
+
);
|
|
501
|
+
const swappedFiles = [];
|
|
502
|
+
for (const file of files) {
|
|
503
|
+
const path4 = isAbsolute(file) ? file : join2(cwd, file);
|
|
504
|
+
if (!existsSync(path4)) continue;
|
|
505
|
+
if (importsPackage(await readFile2(path4, "utf8"), manifest.name)) {
|
|
506
|
+
swappedFiles.push(file);
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
if (swappedFiles.length === 0) {
|
|
510
|
+
return { kind: "imported", config, manifest, components: components2 };
|
|
511
|
+
}
|
|
512
|
+
return { kind: "swapped", config, manifest, components: components2, swappedFiles };
|
|
513
|
+
}
|
|
514
|
+
function resolveImportTarget(state, organization, opts = {}) {
|
|
515
|
+
if (state.kind === "new") return { kind: "new", reason: "first" };
|
|
516
|
+
if (state.kind === "swapped") {
|
|
517
|
+
if (opts.newProject) {
|
|
518
|
+
throw new DirectoryLockedError(state, "Starting a new project");
|
|
519
|
+
}
|
|
520
|
+
return {
|
|
521
|
+
kind: "existing",
|
|
522
|
+
config: state.config,
|
|
523
|
+
components: state.components,
|
|
524
|
+
locked: true
|
|
525
|
+
};
|
|
526
|
+
}
|
|
527
|
+
if (opts.newProject) {
|
|
528
|
+
return { kind: "new", reason: "requested", replaces: state.config };
|
|
529
|
+
}
|
|
530
|
+
if (organization && organization.id !== state.config.orgId) {
|
|
531
|
+
return { kind: "new", reason: "organization", replaces: state.config };
|
|
532
|
+
}
|
|
533
|
+
return {
|
|
534
|
+
kind: "existing",
|
|
535
|
+
config: state.config,
|
|
536
|
+
components: state.components,
|
|
537
|
+
locked: false
|
|
538
|
+
};
|
|
539
|
+
}
|
|
540
|
+
function projectLabel(config) {
|
|
541
|
+
return `${config.projectSlug ?? config.projectId} in ${config.orgSlug ?? config.orgId}`;
|
|
542
|
+
}
|
|
543
|
+
function organizationLabel(organization) {
|
|
544
|
+
if (!organization) return "your active organization";
|
|
545
|
+
return organization.slug ? `${organization.name} (${organization.slug})` : organization.name;
|
|
546
|
+
}
|
|
547
|
+
function describeState(state) {
|
|
548
|
+
switch (state.kind) {
|
|
549
|
+
case "new":
|
|
550
|
+
return "Not linked to a Zoah project yet.";
|
|
551
|
+
case "imported":
|
|
552
|
+
return `Linked to ${projectLabel(state.config)}. Nothing is swapped yet, so the link can still change.`;
|
|
553
|
+
case "swapped":
|
|
554
|
+
return `Swapped to ${state.manifest.name} (${state.swappedFiles.length === 1 ? "1 file" : `${state.swappedFiles.length} files`}), so it stays on ${projectLabel(state.config)}.`;
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
function describeTarget(target, organization) {
|
|
558
|
+
if (target.kind === "existing") {
|
|
559
|
+
return `Adds and updates components in ${projectLabel(target.config)}.`;
|
|
560
|
+
}
|
|
561
|
+
const where = organizationLabel(organization);
|
|
562
|
+
switch (target.reason) {
|
|
563
|
+
case "first":
|
|
564
|
+
return `Creates a project in ${where}.`;
|
|
565
|
+
case "organization":
|
|
566
|
+
return `Creates a project in ${where}, the CLI's organization, and links this directory to it instead of ${projectLabel(target.replaces)}.`;
|
|
567
|
+
case "requested":
|
|
568
|
+
return `Creates a new project in ${where} and links this directory to it instead of ${projectLabel(target.replaces)}.`;
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
function organizationNote(target, organization) {
|
|
572
|
+
if (target.kind === "existing" && target.locked && organization && organization.id !== target.config.orgId) {
|
|
573
|
+
return `The CLI works in ${organizationLabel(organization)}, but a swapped directory stays on its project.`;
|
|
574
|
+
}
|
|
575
|
+
return null;
|
|
576
|
+
}
|
|
577
|
+
var DirectoryLockedError;
|
|
578
|
+
var init_directory_state = __esm({
|
|
579
|
+
"src/config/directory-state.ts"() {
|
|
580
|
+
"use strict";
|
|
581
|
+
init_local();
|
|
582
|
+
DirectoryLockedError = class extends Error {
|
|
583
|
+
constructor(state, action) {
|
|
584
|
+
super(
|
|
585
|
+
`${action} is not possible here: this directory is swapped to ${state.manifest.name} (${state.swappedFiles.length === 1 ? "1 file" : `${state.swappedFiles.length} files`}), so it stays on ${projectLabel(state.config)}. \`zoah import\` still adds and updates components in that project.`
|
|
586
|
+
);
|
|
587
|
+
this.state = state;
|
|
588
|
+
this.name = "DirectoryLockedError";
|
|
589
|
+
}
|
|
590
|
+
};
|
|
591
|
+
}
|
|
592
|
+
});
|
|
593
|
+
|
|
474
594
|
// src/mcp/refs.ts
|
|
475
595
|
function matchRef(options) {
|
|
476
596
|
const trimmed = options.reference.trim();
|
|
@@ -1074,7 +1194,7 @@ var CLI_VERSION;
|
|
|
1074
1194
|
var init_version = __esm({
|
|
1075
1195
|
"src/config/version.ts"() {
|
|
1076
1196
|
"use strict";
|
|
1077
|
-
CLI_VERSION = true ? "0.1.
|
|
1197
|
+
CLI_VERSION = true ? "0.1.9" : "0.0.0-dev";
|
|
1078
1198
|
}
|
|
1079
1199
|
});
|
|
1080
1200
|
|
|
@@ -1179,7 +1299,9 @@ function StatusLine({ children }) {
|
|
|
1179
1299
|
}
|
|
1180
1300
|
function introCopy({
|
|
1181
1301
|
userEmail,
|
|
1182
|
-
zoahUrl
|
|
1302
|
+
zoahUrl,
|
|
1303
|
+
directory,
|
|
1304
|
+
next
|
|
1183
1305
|
}) {
|
|
1184
1306
|
if (!userEmail) {
|
|
1185
1307
|
return {
|
|
@@ -1197,7 +1319,7 @@ function introCopy({
|
|
|
1197
1319
|
}
|
|
1198
1320
|
return {
|
|
1199
1321
|
heading: "Want to rescan?",
|
|
1200
|
-
body: "We will scan your library again and
|
|
1322
|
+
body: directory && next ? `${directory} The next import: ${next}` : "We will scan your library again and update the linked Zoah project.",
|
|
1201
1323
|
goLabel: "Rescan"
|
|
1202
1324
|
};
|
|
1203
1325
|
}
|
|
@@ -1221,12 +1343,14 @@ var init_screens = __esm({
|
|
|
1221
1343
|
userEmail,
|
|
1222
1344
|
zoahUrl,
|
|
1223
1345
|
lastScanAge,
|
|
1224
|
-
sync: sync2
|
|
1346
|
+
sync: sync2,
|
|
1347
|
+
directory,
|
|
1348
|
+
next
|
|
1225
1349
|
}) => function Intro({ value, onFinish }) {
|
|
1226
1350
|
const settled = value !== void 0;
|
|
1227
1351
|
const screenReaderEnabled = useIsScreenReaderEnabled();
|
|
1228
1352
|
const [logoDone, setLogoDone] = useState2(settled || screenReaderEnabled);
|
|
1229
|
-
const copy = introCopy({ userEmail, zoahUrl });
|
|
1353
|
+
const copy = introCopy({ userEmail, zoahUrl, directory, next });
|
|
1230
1354
|
const showStatus = useReveal(150, logoDone);
|
|
1231
1355
|
const showPitch = useReveal(500, logoDone);
|
|
1232
1356
|
const showPicker = useReveal(850, logoDone);
|
|
@@ -1363,6 +1487,9 @@ var init_screens = __esm({
|
|
|
1363
1487
|
};
|
|
1364
1488
|
COMPONENT_LIST_CAP = 20;
|
|
1365
1489
|
DesignSummary = (report) => {
|
|
1490
|
+
if (report.upToDate) {
|
|
1491
|
+
return /* @__PURE__ */ jsx3(Panel, { title: "Nothing new to import", children: /* @__PURE__ */ jsx3(Text3, { children: `The components here are already swapped to ${report.upToDate}. Add a component, then run \`zoah\` again.` }) });
|
|
1492
|
+
}
|
|
1366
1493
|
const checkRow = (key, label, suffix) => /* @__PURE__ */ jsxs3(Box3, { gap: 1, children: [
|
|
1367
1494
|
/* @__PURE__ */ jsx3(Text3, { color: "green", children: "\u2713" }),
|
|
1368
1495
|
/* @__PURE__ */ jsx3(Text3, { children: label }),
|
|
@@ -1554,17 +1681,12 @@ async function runOrganizationSwitch(opts) {
|
|
|
1554
1681
|
const organization = toCliOrganization(chosen);
|
|
1555
1682
|
await writeCredentialOrganization(found, organization);
|
|
1556
1683
|
console.log(`The CLI now works in ${describe(organization)}.`);
|
|
1557
|
-
const
|
|
1558
|
-
if (
|
|
1684
|
+
const state = await readDirectoryState(opts.cwd);
|
|
1685
|
+
if (state.kind !== "new") {
|
|
1686
|
+
const target = resolveImportTarget(state, organization);
|
|
1687
|
+
console.log(dim(` This directory: ${describeState(state)}`));
|
|
1559
1688
|
console.log(
|
|
1560
|
-
dim(
|
|
1561
|
-
` This repo's project is in ${config.orgSlug ?? config.orgId}, and \`zoah import\` keeps updating it.`
|
|
1562
|
-
)
|
|
1563
|
-
);
|
|
1564
|
-
console.log(
|
|
1565
|
-
dim(
|
|
1566
|
-
" To import into this organization instead, remove .zoah/config.json, .zoah/components.json and .zoah/manifest.json."
|
|
1567
|
-
)
|
|
1689
|
+
dim(` Next import here: ${describeTarget(target, organization)}`)
|
|
1568
1690
|
);
|
|
1569
1691
|
}
|
|
1570
1692
|
}
|
|
@@ -1586,7 +1708,7 @@ var init_organization = __esm({
|
|
|
1586
1708
|
"use strict";
|
|
1587
1709
|
init_client();
|
|
1588
1710
|
init_session();
|
|
1589
|
-
|
|
1711
|
+
init_directory_state();
|
|
1590
1712
|
init_refs();
|
|
1591
1713
|
init_colors();
|
|
1592
1714
|
}
|
|
@@ -1673,11 +1795,11 @@ var init_errors = __esm({
|
|
|
1673
1795
|
});
|
|
1674
1796
|
|
|
1675
1797
|
// src/util/ensure-gitignore.ts
|
|
1676
|
-
import { readFile as
|
|
1798
|
+
import { readFile as readFile3 } from "fs/promises";
|
|
1677
1799
|
async function ensureZoahGitignore(cwd) {
|
|
1678
1800
|
const path4 = zoahPaths.gitignore(cwd);
|
|
1679
1801
|
try {
|
|
1680
|
-
const current2 = await
|
|
1802
|
+
const current2 = await readFile3(path4, "utf8");
|
|
1681
1803
|
if (current2 === GITIGNORE_CONTENT) return;
|
|
1682
1804
|
} catch (err) {
|
|
1683
1805
|
if (err.code !== "ENOENT") throw err;
|
|
@@ -25557,14 +25679,14 @@ var init_issues_snapshot = __esm({
|
|
|
25557
25679
|
});
|
|
25558
25680
|
|
|
25559
25681
|
// src/parse/scan.ts
|
|
25560
|
-
import { existsSync, statSync } from "fs";
|
|
25561
|
-
import { isAbsolute, join as
|
|
25682
|
+
import { existsSync as existsSync2, statSync } from "fs";
|
|
25683
|
+
import { isAbsolute as isAbsolute2, join as join3, relative, resolve } from "path";
|
|
25562
25684
|
import { Project } from "ts-morph";
|
|
25563
25685
|
function findTsConfig(cwd) {
|
|
25564
25686
|
const candidates = ["tsconfig.json", "jsconfig.json"];
|
|
25565
25687
|
for (const name of candidates) {
|
|
25566
|
-
const full =
|
|
25567
|
-
if (
|
|
25688
|
+
const full = join3(cwd, name);
|
|
25689
|
+
if (existsSync2(full)) return full;
|
|
25568
25690
|
}
|
|
25569
25691
|
return null;
|
|
25570
25692
|
}
|
|
@@ -25580,17 +25702,17 @@ function loadProject(opts) {
|
|
|
25580
25702
|
/* Preserve */
|
|
25581
25703
|
}
|
|
25582
25704
|
});
|
|
25583
|
-
const scopeAbsolute =
|
|
25584
|
-
if (
|
|
25705
|
+
const scopeAbsolute = isAbsolute2(opts.scopePath) ? opts.scopePath : resolve(opts.cwd, opts.scopePath);
|
|
25706
|
+
if (existsSync2(scopeAbsolute)) {
|
|
25585
25707
|
const stat = statSync(scopeAbsolute);
|
|
25586
25708
|
if (stat.isDirectory()) {
|
|
25587
25709
|
const patterns = SOURCE_EXTENSIONS.map(
|
|
25588
|
-
(ext) =>
|
|
25710
|
+
(ext) => join3(scopeAbsolute, `**/*.${ext}`)
|
|
25589
25711
|
);
|
|
25590
25712
|
for (const dir of IGNORED_DIRS) {
|
|
25591
|
-
patterns.push(`!${
|
|
25713
|
+
patterns.push(`!${join3(scopeAbsolute, `**/${dir}/**`)}`);
|
|
25592
25714
|
}
|
|
25593
|
-
patterns.push(`!${
|
|
25715
|
+
patterns.push(`!${join3(scopeAbsolute, "**/*.d.ts")}`);
|
|
25594
25716
|
project.addSourceFilesAtPaths(patterns);
|
|
25595
25717
|
} else {
|
|
25596
25718
|
project.addSourceFileAtPathIfExists(scopeAbsolute);
|
|
@@ -25740,7 +25862,7 @@ var init_classify = __esm({
|
|
|
25740
25862
|
});
|
|
25741
25863
|
|
|
25742
25864
|
// src/parse/entry-points.ts
|
|
25743
|
-
import { existsSync as
|
|
25865
|
+
import { existsSync as existsSync3 } from "fs";
|
|
25744
25866
|
import { resolve as resolve2 } from "path";
|
|
25745
25867
|
function isFrameworkReservedFile(filePath) {
|
|
25746
25868
|
const base = filePath.split("/").pop() ?? "";
|
|
@@ -25752,7 +25874,7 @@ function findEntrySkips(project, cwd) {
|
|
|
25752
25874
|
const entryFiles = [];
|
|
25753
25875
|
for (const candidate of ENTRY_CANDIDATES) {
|
|
25754
25876
|
const fullPath = resolve2(cwd, candidate);
|
|
25755
|
-
if (!
|
|
25877
|
+
if (!existsSync3(fullPath)) continue;
|
|
25756
25878
|
let sf = project.getSourceFile(fullPath);
|
|
25757
25879
|
if (!sf) {
|
|
25758
25880
|
sf = project.addSourceFileAtPathIfExists(fullPath) ?? void 0;
|
|
@@ -25885,10 +26007,10 @@ var init_styled_components = __esm({
|
|
|
25885
26007
|
});
|
|
25886
26008
|
|
|
25887
26009
|
// src/parse/module-resolution.ts
|
|
25888
|
-
import { existsSync as
|
|
25889
|
-
import { dirname as dirname2, isAbsolute as
|
|
26010
|
+
import { existsSync as existsSync4, readFileSync, readdirSync, statSync as statSync2 } from "fs";
|
|
26011
|
+
import { dirname as dirname2, isAbsolute as isAbsolute3, join as join4, relative as relative2, resolve as resolve3, sep } from "path";
|
|
25890
26012
|
function readTsconfig(absPath) {
|
|
25891
|
-
if (!
|
|
26013
|
+
if (!existsSync4(absPath)) return null;
|
|
25892
26014
|
let raw;
|
|
25893
26015
|
try {
|
|
25894
26016
|
raw = readFileSync(absPath, "utf8");
|
|
@@ -25906,7 +26028,7 @@ function readTsconfig(absPath) {
|
|
|
25906
26028
|
function loadTsconfigPaths(cwd) {
|
|
25907
26029
|
const candidates = ["tsconfig.json", "jsconfig.json"];
|
|
25908
26030
|
for (const name of candidates) {
|
|
25909
|
-
const path4 =
|
|
26031
|
+
const path4 = join4(cwd, name);
|
|
25910
26032
|
const tsconfig = readTsconfig(path4);
|
|
25911
26033
|
if (!tsconfig) continue;
|
|
25912
26034
|
const opts = tsconfig.compilerOptions;
|
|
@@ -25956,13 +26078,13 @@ function expandWorkspaceGlob(rootCwd, pattern) {
|
|
|
25956
26078
|
const starIdx = cleaned.indexOf("*");
|
|
25957
26079
|
if (starIdx < 0) {
|
|
25958
26080
|
const abs = resolve3(rootCwd, cleaned);
|
|
25959
|
-
return
|
|
26081
|
+
return existsSync4(join4(abs, "package.json")) ? [abs] : [];
|
|
25960
26082
|
}
|
|
25961
26083
|
const prefix = cleaned.slice(0, starIdx).replace(/\/$/, "");
|
|
25962
26084
|
const suffix = cleaned.slice(starIdx).replace(/^\*+\/?/, "");
|
|
25963
26085
|
if (suffix.length > 0) return [];
|
|
25964
26086
|
const dir = resolve3(rootCwd, prefix);
|
|
25965
|
-
if (!
|
|
26087
|
+
if (!existsSync4(dir)) return [];
|
|
25966
26088
|
let entries;
|
|
25967
26089
|
try {
|
|
25968
26090
|
entries = readdirSync(dir);
|
|
@@ -25972,19 +26094,19 @@ function expandWorkspaceGlob(rootCwd, pattern) {
|
|
|
25972
26094
|
const out = [];
|
|
25973
26095
|
for (const entry of entries) {
|
|
25974
26096
|
if (entry.startsWith(".")) continue;
|
|
25975
|
-
const child =
|
|
26097
|
+
const child = join4(dir, entry);
|
|
25976
26098
|
try {
|
|
25977
26099
|
if (!statSync2(child).isDirectory()) continue;
|
|
25978
26100
|
} catch {
|
|
25979
26101
|
continue;
|
|
25980
26102
|
}
|
|
25981
|
-
if (
|
|
26103
|
+
if (existsSync4(join4(child, "package.json"))) out.push(child);
|
|
25982
26104
|
}
|
|
25983
26105
|
return out;
|
|
25984
26106
|
}
|
|
25985
26107
|
function readPackageJson(packageRoot) {
|
|
25986
|
-
const path4 =
|
|
25987
|
-
if (!
|
|
26108
|
+
const path4 = join4(packageRoot, "package.json");
|
|
26109
|
+
if (!existsSync4(path4)) return null;
|
|
25988
26110
|
try {
|
|
25989
26111
|
const parsed = JSON.parse(readFileSync(path4, "utf8"));
|
|
25990
26112
|
if (parsed && typeof parsed === "object") {
|
|
@@ -25996,8 +26118,8 @@ function readPackageJson(packageRoot) {
|
|
|
25996
26118
|
}
|
|
25997
26119
|
}
|
|
25998
26120
|
function readPnpmWorkspaceGlobs(cwd) {
|
|
25999
|
-
const path4 =
|
|
26000
|
-
if (!
|
|
26121
|
+
const path4 = join4(cwd, "pnpm-workspace.yaml");
|
|
26122
|
+
if (!existsSync4(path4)) return [];
|
|
26001
26123
|
let raw;
|
|
26002
26124
|
try {
|
|
26003
26125
|
raw = readFileSync(path4, "utf8");
|
|
@@ -26050,8 +26172,8 @@ function loadWorkspacePackages(cwd) {
|
|
|
26050
26172
|
});
|
|
26051
26173
|
}
|
|
26052
26174
|
}
|
|
26053
|
-
const lernaPath =
|
|
26054
|
-
if (
|
|
26175
|
+
const lernaPath = join4(cwd, "lerna.json");
|
|
26176
|
+
if (existsSync4(lernaPath)) {
|
|
26055
26177
|
try {
|
|
26056
26178
|
const lerna = JSON.parse(readFileSync(lernaPath, "utf8"));
|
|
26057
26179
|
if (Array.isArray(lerna.packages)) {
|
|
@@ -26072,7 +26194,7 @@ function findOwningWorkspace(workspaces, absPath) {
|
|
|
26072
26194
|
let best = null;
|
|
26073
26195
|
for (const ws of workspaces) {
|
|
26074
26196
|
const rel = relative2(ws.root, absPath);
|
|
26075
|
-
if (rel.startsWith("..") ||
|
|
26197
|
+
if (rel.startsWith("..") || isAbsolute3(rel)) continue;
|
|
26076
26198
|
if (!best || ws.root.length > best.root.length) best = ws;
|
|
26077
26199
|
}
|
|
26078
26200
|
return best;
|
|
@@ -26177,8 +26299,8 @@ function detectBuildTimeTransforms(cwd) {
|
|
|
26177
26299
|
const detected = [];
|
|
26178
26300
|
const seen = /* @__PURE__ */ new Set();
|
|
26179
26301
|
for (const candidate of TRANSFORM_CONFIG_CANDIDATES) {
|
|
26180
|
-
const path4 =
|
|
26181
|
-
if (!
|
|
26302
|
+
const path4 = join4(cwd, candidate);
|
|
26303
|
+
if (!existsSync4(path4)) continue;
|
|
26182
26304
|
let raw;
|
|
26183
26305
|
try {
|
|
26184
26306
|
raw = readFileSync(path4, "utf8");
|
|
@@ -26206,7 +26328,7 @@ function buildModuleResolutionContext(cwd) {
|
|
|
26206
26328
|
function findOwningPackageRoot(absPath) {
|
|
26207
26329
|
let dir = dirname2(absPath);
|
|
26208
26330
|
for (let i3 = 0; i3 < MAX_PACKAGE_WALK_DEPTH; i3++) {
|
|
26209
|
-
if (
|
|
26331
|
+
if (existsSync4(join4(dir, "package.json"))) return dir;
|
|
26210
26332
|
const parent = dirname2(dir);
|
|
26211
26333
|
if (parent === dir) return null;
|
|
26212
26334
|
dir = parent;
|
|
@@ -26221,7 +26343,7 @@ function resolveImport(ctx, sourceFile, decl, issueCtx) {
|
|
|
26221
26343
|
const line = decl.getStartLineNumber();
|
|
26222
26344
|
const resolvedSf = decl.getModuleSpecifierSourceFile();
|
|
26223
26345
|
const resolvedAbs = resolvedSf?.getFilePath() ?? null;
|
|
26224
|
-
const isBareSpecifier = !specifier.startsWith(".") && !
|
|
26346
|
+
const isBareSpecifier = !specifier.startsWith(".") && !isAbsolute3(specifier);
|
|
26225
26347
|
const tsconfigMatch = isBareSpecifier && ctx.tsconfigPaths ? matchTsconfigPath(ctx.tsconfigPaths, specifier) : null;
|
|
26226
26348
|
if (tsconfigMatch) {
|
|
26227
26349
|
const resolvedTo = resolvedAbs ? relative2(ctx.cwd, resolvedAbs) || resolvedAbs : tsconfigMatch.resolvedTargets[0] ? relative2(ctx.cwd, tsconfigMatch.resolvedTargets[0]) || tsconfigMatch.resolvedTargets[0] : tsconfigMatch.pattern;
|
|
@@ -26757,16 +26879,16 @@ var init_discover = __esm({
|
|
|
26757
26879
|
});
|
|
26758
26880
|
|
|
26759
26881
|
// src/parse/tailwind-tokens.ts
|
|
26760
|
-
import { existsSync as
|
|
26761
|
-
import { join as
|
|
26882
|
+
import { existsSync as existsSync5, readFileSync as readFileSync2 } from "fs";
|
|
26883
|
+
import { join as join5 } from "path";
|
|
26762
26884
|
function cssImportsTailwind(cssText) {
|
|
26763
26885
|
return /@import\s+["']tailwindcss["']/.test(cssText);
|
|
26764
26886
|
}
|
|
26765
26887
|
function findThemeCssFiles(cwd) {
|
|
26766
26888
|
const found = [];
|
|
26767
26889
|
for (const rel of CSS_ENTRY_CANDIDATES) {
|
|
26768
|
-
const p4 =
|
|
26769
|
-
if (!
|
|
26890
|
+
const p4 = join5(cwd, rel);
|
|
26891
|
+
if (!existsSync5(p4)) continue;
|
|
26770
26892
|
const text = safeRead(p4);
|
|
26771
26893
|
if (text && (cssImportsTailwind(text) || /:root\s*\{|@theme\b/.test(text))) {
|
|
26772
26894
|
found.push(p4);
|
|
@@ -27161,8 +27283,8 @@ var init_tailwind_engine = __esm({
|
|
|
27161
27283
|
});
|
|
27162
27284
|
|
|
27163
27285
|
// src/parse/tailwind.ts
|
|
27164
|
-
import { existsSync as
|
|
27165
|
-
import { join as
|
|
27286
|
+
import { existsSync as existsSync6 } from "fs";
|
|
27287
|
+
import { join as join6 } from "path";
|
|
27166
27288
|
import { createJiti } from "jiti";
|
|
27167
27289
|
function findConfig(cwd) {
|
|
27168
27290
|
const candidates = [
|
|
@@ -27172,8 +27294,8 @@ function findConfig(cwd) {
|
|
|
27172
27294
|
"tailwind.config.mjs"
|
|
27173
27295
|
];
|
|
27174
27296
|
for (const name of candidates) {
|
|
27175
|
-
const p4 =
|
|
27176
|
-
if (
|
|
27297
|
+
const p4 = join6(cwd, name);
|
|
27298
|
+
if (existsSync6(p4)) return p4;
|
|
27177
27299
|
}
|
|
27178
27300
|
return null;
|
|
27179
27301
|
}
|
|
@@ -29198,15 +29320,15 @@ var init_plain_css = __esm({
|
|
|
29198
29320
|
});
|
|
29199
29321
|
|
|
29200
29322
|
// src/parse/css-resolution.ts
|
|
29201
|
-
import { dirname as dirname4, isAbsolute as
|
|
29202
|
-
import { existsSync as
|
|
29323
|
+
import { dirname as dirname4, isAbsolute as isAbsolute4, resolve as resolve4 } from "path";
|
|
29324
|
+
import { existsSync as existsSync7 } from "fs";
|
|
29203
29325
|
import {
|
|
29204
29326
|
Node as Node8
|
|
29205
29327
|
} from "ts-morph";
|
|
29206
29328
|
function resolveImportPath(fromFile, specifier) {
|
|
29207
|
-
if (!specifier.startsWith(".") && !
|
|
29208
|
-
const base =
|
|
29209
|
-
if (
|
|
29329
|
+
if (!specifier.startsWith(".") && !isAbsolute4(specifier)) return null;
|
|
29330
|
+
const base = isAbsolute4(specifier) ? specifier : resolve4(dirname4(fromFile), specifier);
|
|
29331
|
+
if (existsSync7(base)) return base;
|
|
29210
29332
|
return null;
|
|
29211
29333
|
}
|
|
29212
29334
|
function buildSourceFileResolverContext(sourceFile, emit, viewportWidth = 0) {
|
|
@@ -89897,8 +90019,8 @@ var init_dist4 = __esm({
|
|
|
89897
90019
|
});
|
|
89898
90020
|
|
|
89899
90021
|
// src/codemod/wrap-with-zoah.ts
|
|
89900
|
-
import { existsSync as
|
|
89901
|
-
import { join as
|
|
90022
|
+
import { existsSync as existsSync8 } from "fs";
|
|
90023
|
+
import { join as join7, resolve as resolve5 } from "path";
|
|
89902
90024
|
import {
|
|
89903
90025
|
Node as Node10,
|
|
89904
90026
|
Project as Project3,
|
|
@@ -89906,8 +90028,8 @@ import {
|
|
|
89906
90028
|
} from "ts-morph";
|
|
89907
90029
|
function findTsConfig2(cwd) {
|
|
89908
90030
|
for (const name of ["tsconfig.json", "jsconfig.json"]) {
|
|
89909
|
-
const full =
|
|
89910
|
-
if (
|
|
90031
|
+
const full = join7(cwd, name);
|
|
90032
|
+
if (existsSync8(full)) return full;
|
|
89911
90033
|
}
|
|
89912
90034
|
return null;
|
|
89913
90035
|
}
|
|
@@ -90817,12 +90939,9 @@ function wrapSingleFile(file, filePath, entry, packageName, rootForwardingSurfac
|
|
|
90817
90939
|
ensureAliasedImport(file, exportName, aliasName, moduleSpecifier);
|
|
90818
90940
|
return { kind: "wrapped", infoFindings };
|
|
90819
90941
|
}
|
|
90820
|
-
function sourceFileForManifestEntry(key, entry) {
|
|
90821
|
-
return entry.sourceFile ?? key.split("#")[0] ?? key;
|
|
90822
|
-
}
|
|
90823
90942
|
function groupManifestEntries(components2) {
|
|
90824
90943
|
return Object.entries(components2).map(([key, entry]) => ({
|
|
90825
|
-
filePath:
|
|
90944
|
+
filePath: manifestSourceFile(key, entry),
|
|
90826
90945
|
entry
|
|
90827
90946
|
}));
|
|
90828
90947
|
}
|
|
@@ -90847,7 +90966,7 @@ async function wrapWithZoah(opts) {
|
|
|
90847
90966
|
}
|
|
90848
90967
|
for (const [relPath, entries] of fileEntries) {
|
|
90849
90968
|
const absPath = resolve5(opts.cwd, relPath);
|
|
90850
|
-
if (!
|
|
90969
|
+
if (!existsSync8(absPath)) {
|
|
90851
90970
|
result.issues.push(
|
|
90852
90971
|
makeIssue({
|
|
90853
90972
|
code: "CODEMOD_SOURCE_FILE_NOT_FOUND",
|
|
@@ -90980,6 +91099,7 @@ var init_wrap_with_zoah = __esm({
|
|
|
90980
91099
|
"src/codemod/wrap-with-zoah.ts"() {
|
|
90981
91100
|
"use strict";
|
|
90982
91101
|
init_cli_import();
|
|
91102
|
+
init_local();
|
|
90983
91103
|
init_discover();
|
|
90984
91104
|
init_jsx_peel();
|
|
90985
91105
|
init_props();
|
|
@@ -90988,17 +91108,17 @@ var init_wrap_with_zoah = __esm({
|
|
|
90988
91108
|
});
|
|
90989
91109
|
|
|
90990
91110
|
// src/codemod/install-package.ts
|
|
90991
|
-
import { existsSync as
|
|
90992
|
-
import { chmod as chmod2, readFile as
|
|
90993
|
-
import { dirname as dirname5, join as
|
|
91111
|
+
import { existsSync as existsSync9 } from "fs";
|
|
91112
|
+
import { chmod as chmod2, readFile as readFile4, writeFile as writeFile2 } from "fs/promises";
|
|
91113
|
+
import { dirname as dirname5, join as join8 } from "path";
|
|
90994
91114
|
import { homedir as homedir2 } from "os";
|
|
90995
91115
|
import { spawn } from "child_process";
|
|
90996
91116
|
import { request as request3 } from "undici";
|
|
90997
91117
|
function detectPackageManager(cwd) {
|
|
90998
91118
|
let dir = cwd;
|
|
90999
91119
|
while (true) {
|
|
91000
|
-
if (
|
|
91001
|
-
if (
|
|
91120
|
+
if (existsSync9(join8(dir, "pnpm-lock.yaml"))) return "pnpm";
|
|
91121
|
+
if (existsSync9(join8(dir, "yarn.lock"))) return "yarn";
|
|
91002
91122
|
const parent = dirname5(dir);
|
|
91003
91123
|
if (parent === dir) break;
|
|
91004
91124
|
dir = parent;
|
|
@@ -91006,11 +91126,11 @@ function detectPackageManager(cwd) {
|
|
|
91006
91126
|
return "npm";
|
|
91007
91127
|
}
|
|
91008
91128
|
async function ensureNpmrcRegistry(cwd, registryUrl) {
|
|
91009
|
-
const npmrcPath =
|
|
91129
|
+
const npmrcPath = join8(cwd, ".npmrc");
|
|
91010
91130
|
const desired = `@zoah:registry=${registryUrl}`;
|
|
91011
91131
|
let existing = "";
|
|
91012
|
-
if (
|
|
91013
|
-
existing = await
|
|
91132
|
+
if (existsSync9(npmrcPath)) {
|
|
91133
|
+
existing = await readFile4(npmrcPath, "utf8");
|
|
91014
91134
|
}
|
|
91015
91135
|
const lines = existing.split(/\r?\n/);
|
|
91016
91136
|
const idx = lines.findIndex((l) => l.trim().startsWith("@zoah:registry="));
|
|
@@ -91029,9 +91149,9 @@ function registryHostOf(registryUrl) {
|
|
|
91029
91149
|
}
|
|
91030
91150
|
async function readNpmrcAuthToken(cwd, registryUrl) {
|
|
91031
91151
|
const prefix = `//${registryHostOf(registryUrl)}/:_authToken=`;
|
|
91032
|
-
for (const npmrcPath of [
|
|
91033
|
-
if (!
|
|
91034
|
-
const content = await
|
|
91152
|
+
for (const npmrcPath of [join8(cwd, ".npmrc"), join8(homedir2(), ".npmrc")]) {
|
|
91153
|
+
if (!existsSync9(npmrcPath)) continue;
|
|
91154
|
+
const content = await readFile4(npmrcPath, "utf8");
|
|
91035
91155
|
const line = content.split(/\r?\n/).map((l) => l.trim()).find((l) => l.startsWith(prefix));
|
|
91036
91156
|
if (line) return line.slice(prefix.length);
|
|
91037
91157
|
}
|
|
@@ -91066,12 +91186,12 @@ function isNpmrcTracked(cwd) {
|
|
|
91066
91186
|
});
|
|
91067
91187
|
}
|
|
91068
91188
|
async function ensureNpmrcAuthToken(cwd, registryUrl, token) {
|
|
91069
|
-
const npmrcPath =
|
|
91189
|
+
const npmrcPath = join8(cwd, ".npmrc");
|
|
91070
91190
|
const host = registryHostOf(registryUrl);
|
|
91071
91191
|
const desired = `//${host}/:_authToken=${token}`;
|
|
91072
91192
|
let existing = "";
|
|
91073
|
-
if (
|
|
91074
|
-
existing = await
|
|
91193
|
+
if (existsSync9(npmrcPath)) {
|
|
91194
|
+
existing = await readFile4(npmrcPath, "utf8");
|
|
91075
91195
|
}
|
|
91076
91196
|
const lines = existing.split(/\r?\n/);
|
|
91077
91197
|
const idx = lines.findIndex(
|
|
@@ -91092,10 +91212,10 @@ async function ensureNpmrcAuthToken(cwd, registryUrl, token) {
|
|
|
91092
91212
|
await chmod2(npmrcPath, 384);
|
|
91093
91213
|
}
|
|
91094
91214
|
async function ensureGitignoreHasNpmrc(cwd) {
|
|
91095
|
-
const gitignorePath =
|
|
91215
|
+
const gitignorePath = join8(cwd, ".gitignore");
|
|
91096
91216
|
let existing = "";
|
|
91097
|
-
if (
|
|
91098
|
-
existing = await
|
|
91217
|
+
if (existsSync9(gitignorePath)) {
|
|
91218
|
+
existing = await readFile4(gitignorePath, "utf8");
|
|
91099
91219
|
const has = existing.split(/\r?\n/).some((l) => l.trim() === ".npmrc" || l.trim() === "/.npmrc");
|
|
91100
91220
|
if (has) return false;
|
|
91101
91221
|
}
|
|
@@ -91105,11 +91225,11 @@ async function ensureGitignoreHasNpmrc(cwd) {
|
|
|
91105
91225
|
return true;
|
|
91106
91226
|
}
|
|
91107
91227
|
async function addDependencyToPackageJson(cwd, packageName, version) {
|
|
91108
|
-
const pkgPath =
|
|
91109
|
-
if (!
|
|
91228
|
+
const pkgPath = join8(cwd, "package.json");
|
|
91229
|
+
if (!existsSync9(pkgPath)) {
|
|
91110
91230
|
throw new Error("No package.json found at " + cwd);
|
|
91111
91231
|
}
|
|
91112
|
-
const raw = await
|
|
91232
|
+
const raw = await readFile4(pkgPath, "utf8");
|
|
91113
91233
|
const pkg = JSON.parse(raw);
|
|
91114
91234
|
const deps = pkg.dependencies ?? {};
|
|
91115
91235
|
const desired = `^${version}`;
|
|
@@ -91239,7 +91359,7 @@ async function runSwapCore(opts) {
|
|
|
91239
91359
|
const swapped = [];
|
|
91240
91360
|
const skipped = [];
|
|
91241
91361
|
for (const [manifestKey, comp] of Object.entries(components2)) {
|
|
91242
|
-
const filePath = comp
|
|
91362
|
+
const filePath = manifestSourceFile(manifestKey, comp);
|
|
91243
91363
|
if (changedFiles.has(filePath)) {
|
|
91244
91364
|
swapped.push(comp.packageExport);
|
|
91245
91365
|
} else {
|
|
@@ -91394,18 +91514,19 @@ var init_swap = __esm({
|
|
|
91394
91514
|
// src/commands/import.ts
|
|
91395
91515
|
var import_exports = {};
|
|
91396
91516
|
__export(import_exports, {
|
|
91517
|
+
buildDesignUrl: () => buildDesignUrl,
|
|
91397
91518
|
runImport: () => runImport,
|
|
91398
91519
|
runImportLocalPipeline: () => runImportLocalPipeline,
|
|
91399
91520
|
runImportSubmit: () => runImportSubmit
|
|
91400
91521
|
});
|
|
91401
|
-
import { readFile as
|
|
91402
|
-
import { existsSync as
|
|
91403
|
-
import { isAbsolute as
|
|
91522
|
+
import { readFile as readFile5 } from "fs/promises";
|
|
91523
|
+
import { existsSync as existsSync10 } from "fs";
|
|
91524
|
+
import { isAbsolute as isAbsolute5, join as join9, relative as relative5 } from "path";
|
|
91404
91525
|
async function readPackageJsonName(cwd) {
|
|
91405
|
-
const path4 =
|
|
91406
|
-
if (!
|
|
91526
|
+
const path4 = join9(cwd, "package.json");
|
|
91527
|
+
if (!existsSync10(path4)) return null;
|
|
91407
91528
|
try {
|
|
91408
|
-
const raw = await
|
|
91529
|
+
const raw = await readFile5(path4, "utf8");
|
|
91409
91530
|
const parsed = JSON.parse(raw);
|
|
91410
91531
|
return parsed.name ?? null;
|
|
91411
91532
|
} catch {
|
|
@@ -91504,14 +91625,11 @@ function componentIdsForReimport(components2, manifest, cwd) {
|
|
|
91504
91625
|
return [...ids];
|
|
91505
91626
|
}
|
|
91506
91627
|
function manifestKeyForPath(cwd, filePath) {
|
|
91507
|
-
return
|
|
91628
|
+
return isAbsolute5(filePath) ? relative5(cwd, filePath) : filePath;
|
|
91508
91629
|
}
|
|
91509
91630
|
function manifestKeyForComponent(cwd, filePath, packageExport) {
|
|
91510
91631
|
return `${manifestKeyForPath(cwd, filePath)}#${packageExport}`;
|
|
91511
91632
|
}
|
|
91512
|
-
function manifestSourceFile(key, entry) {
|
|
91513
|
-
return entry.sourceFile ?? key.split("#")[0] ?? key;
|
|
91514
|
-
}
|
|
91515
91633
|
function findManifestEntryForComponent(manifest, cwd, filePath, packageExport) {
|
|
91516
91634
|
const sourceFile = manifestKeyForPath(cwd, filePath);
|
|
91517
91635
|
const keyed = manifest[`${sourceFile}#${packageExport}`];
|
|
@@ -91528,8 +91646,12 @@ async function runImportLocalPipeline(opts) {
|
|
|
91528
91646
|
await ensureZoahGitignore(opts.cwd);
|
|
91529
91647
|
const baseUrl = opts.baseUrl ?? creds.baseUrl;
|
|
91530
91648
|
const branchName = opts.branch ?? process.env.ZOAH_BRANCH ?? process.env.OPACITY_BRANCH ?? null;
|
|
91531
|
-
const
|
|
91532
|
-
const
|
|
91649
|
+
const state = await readDirectoryState(opts.cwd);
|
|
91650
|
+
const target = resolveImportTarget(state, creds.organization, {
|
|
91651
|
+
newProject: opts.newProject
|
|
91652
|
+
});
|
|
91653
|
+
const existingConfig = target.kind === "existing" ? target.config : null;
|
|
91654
|
+
const existingComponentsManifest = target.kind === "existing" ? target.components : null;
|
|
91533
91655
|
const api = ApiClient.fromCredentials(creds, baseUrl);
|
|
91534
91656
|
const commitSha = getCommitSha(opts.cwd);
|
|
91535
91657
|
const issueCtx = createIssueContext({ commitSha });
|
|
@@ -91547,7 +91669,22 @@ async function runImportLocalPipeline(opts) {
|
|
|
91547
91669
|
const entrySkip = findEntrySkips(scan2.project, opts.cwd);
|
|
91548
91670
|
const preBuildIssues = [];
|
|
91549
91671
|
const relPath = (abs) => relative5(opts.cwd, abs);
|
|
91672
|
+
const swappedExports = /* @__PURE__ */ new Set();
|
|
91673
|
+
if (state.kind === "swapped") {
|
|
91674
|
+
const swappedFiles = new Set(state.swappedFiles);
|
|
91675
|
+
for (const [key, entry] of Object.entries(state.components)) {
|
|
91676
|
+
const file = manifestSourceFile(key, entry);
|
|
91677
|
+
if (swappedFiles.has(file)) {
|
|
91678
|
+
swappedExports.add(`${file}#${entry.packageExport}`);
|
|
91679
|
+
}
|
|
91680
|
+
}
|
|
91681
|
+
}
|
|
91682
|
+
const alreadySwapped = [];
|
|
91550
91683
|
const filteredComponents = fullDiscovery.components.filter((c3) => {
|
|
91684
|
+
if (swappedExports.has(`${relPath(c3.filePath)}#${c3.name}`)) {
|
|
91685
|
+
alreadySwapped.push(c3);
|
|
91686
|
+
return false;
|
|
91687
|
+
}
|
|
91551
91688
|
if (entrySkip.skippedFilePaths.has(c3.filePath)) {
|
|
91552
91689
|
preBuildIssues.push(
|
|
91553
91690
|
makeIssue({
|
|
@@ -91599,6 +91736,10 @@ async function runImportLocalPipeline(opts) {
|
|
|
91599
91736
|
return {
|
|
91600
91737
|
payload,
|
|
91601
91738
|
filteredComponents,
|
|
91739
|
+
alreadySwapped,
|
|
91740
|
+
state,
|
|
91741
|
+
target,
|
|
91742
|
+
organization: creds.organization,
|
|
91602
91743
|
preBuildIssues,
|
|
91603
91744
|
importPhaseIssues,
|
|
91604
91745
|
scanSourceFileCount: scan2.sourceFiles.length,
|
|
@@ -91636,6 +91777,7 @@ async function runImportSubmit(local, opts, onProgress) {
|
|
|
91636
91777
|
const {
|
|
91637
91778
|
payload,
|
|
91638
91779
|
filteredComponents,
|
|
91780
|
+
alreadySwapped,
|
|
91639
91781
|
buildResult,
|
|
91640
91782
|
baseUrl,
|
|
91641
91783
|
branchName,
|
|
@@ -91678,7 +91820,7 @@ async function runImportSubmit(local, opts, onProgress) {
|
|
|
91678
91820
|
});
|
|
91679
91821
|
}
|
|
91680
91822
|
const discoveredManifestKeys = new Set(
|
|
91681
|
-
filteredComponents.map(
|
|
91823
|
+
[...filteredComponents, ...alreadySwapped].map(
|
|
91682
91824
|
(component) => manifestKeyForPath(opts.cwd, component.filePath)
|
|
91683
91825
|
)
|
|
91684
91826
|
);
|
|
@@ -91758,12 +91900,21 @@ async function runImport(opts) {
|
|
|
91758
91900
|
try {
|
|
91759
91901
|
local = await runImportLocalPipeline(opts);
|
|
91760
91902
|
} catch (err) {
|
|
91761
|
-
scanSpinner.fail(
|
|
91903
|
+
scanSpinner.fail(
|
|
91904
|
+
err instanceof DirectoryLockedError ? "This directory is swapped." : "Scan failed."
|
|
91905
|
+
);
|
|
91762
91906
|
throw err;
|
|
91763
91907
|
}
|
|
91908
|
+
const swappedCount = local.alreadySwapped.length;
|
|
91764
91909
|
scanSpinner.succeed(
|
|
91765
|
-
`Found ${bold(pluralize(local.filteredComponents.length, "first-party component"))}
|
|
91910
|
+
`Found ${bold(pluralize(local.filteredComponents.length, "first-party component"))}` + (swappedCount > 0 ? ` to import, plus ${pluralize(swappedCount, "swapped component")} already in Zoah` : "") + "."
|
|
91911
|
+
);
|
|
91912
|
+
console.log(` ${dim("This directory:")} ${describeState(local.state)}`);
|
|
91913
|
+
console.log(
|
|
91914
|
+
` ${dim("This import:")} ${describeTarget(local.target, local.organization)}`
|
|
91766
91915
|
);
|
|
91916
|
+
const note = organizationNote(local.target, local.organization);
|
|
91917
|
+
if (note) console.log(dim(` ${note}`));
|
|
91767
91918
|
const tailwind = local.tailwind;
|
|
91768
91919
|
if (tailwind.available && tailwind.configPath) {
|
|
91769
91920
|
console.log(` Tailwind config: ${bold(tailwind.configPath)}.`);
|
|
@@ -91838,6 +91989,16 @@ async function runImport(opts) {
|
|
|
91838
91989
|
console.log(` ${dim("View in Zoah:")} ${bold(url)}`);
|
|
91839
91990
|
}
|
|
91840
91991
|
};
|
|
91992
|
+
if (payload.components.length === 0 && swappedCount > 0) {
|
|
91993
|
+
await flushIssueOutput();
|
|
91994
|
+
console.log("");
|
|
91995
|
+
console.log(
|
|
91996
|
+
` Nothing new to import. The components here are already swapped to ${bold(
|
|
91997
|
+
local.state.kind === "swapped" ? local.state.manifest.name : "its package"
|
|
91998
|
+
)}. Add a component, then run \`zoah import\` again.`
|
|
91999
|
+
);
|
|
92000
|
+
return;
|
|
92001
|
+
}
|
|
91841
92002
|
if (opts.dryRun) {
|
|
91842
92003
|
if (opts.swap) {
|
|
91843
92004
|
console.log(
|
|
@@ -91966,6 +92127,7 @@ var init_import = __esm({
|
|
|
91966
92127
|
init_cli_import();
|
|
91967
92128
|
init_dist4();
|
|
91968
92129
|
init_swap();
|
|
92130
|
+
init_directory_state();
|
|
91969
92131
|
}
|
|
91970
92132
|
});
|
|
91971
92133
|
|
|
@@ -112586,7 +112748,7 @@ import {
|
|
|
112586
112748
|
} from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
112587
112749
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
112588
112750
|
import { z as z59 } from "zod";
|
|
112589
|
-
import { existsSync as
|
|
112751
|
+
import { existsSync as existsSync11 } from "fs";
|
|
112590
112752
|
import { statSync as statSync3 } from "fs";
|
|
112591
112753
|
function parseJsonObject(text) {
|
|
112592
112754
|
const value = JSON.parse(text);
|
|
@@ -112678,7 +112840,7 @@ async function runMcpServer(options) {
|
|
|
112678
112840
|
return `The credential now points at ${credentialInstance}, but this session is open against ${session.baseUrl}. Refusing to send this call to a different instance than the one you are working on: the token would be presented to the wrong server, and on a development machine the two are commonly local dev and production. Nothing was sent. Either restore the credential for ${session.baseUrl} (\`zoah login\` in that directory), or call \`disconnect\` and then \`connect\` to move this session to ${credentialInstance} deliberately.`;
|
|
112679
112841
|
}
|
|
112680
112842
|
function loginScope() {
|
|
112681
|
-
return
|
|
112843
|
+
return existsSync11(zoahPaths.localCredentials(process.cwd())) || existsSync11(legacyOpacityPaths.localCredentials(process.cwd())) ? "local" : "global";
|
|
112682
112844
|
}
|
|
112683
112845
|
let pendingSignIn = null;
|
|
112684
112846
|
let selectedOrganization = null;
|
|
@@ -112758,7 +112920,7 @@ async function runMcpServer(options) {
|
|
|
112758
112920
|
pinnedBy: "the human's selection"
|
|
112759
112921
|
} : null;
|
|
112760
112922
|
}
|
|
112761
|
-
function
|
|
112923
|
+
function organizationLabel2(fallbackId) {
|
|
112762
112924
|
const working = describeWorkingIn(fallbackId);
|
|
112763
112925
|
return working?.slug ?? working?.id ?? fallbackId;
|
|
112764
112926
|
}
|
|
@@ -112781,7 +112943,7 @@ async function runMcpServer(options) {
|
|
|
112781
112943
|
const dropped = session ? {
|
|
112782
112944
|
project: session.projectId,
|
|
112783
112945
|
branch: session.branchSlug,
|
|
112784
|
-
fromOrganization:
|
|
112946
|
+
fromOrganization: organizationLabel2(session.orgId),
|
|
112785
112947
|
toOrganization: to.slug ?? to.organizationId
|
|
112786
112948
|
} : void 0;
|
|
112787
112949
|
if (session) await teardownSession();
|
|
@@ -114274,7 +114436,7 @@ __export(init_exports, {
|
|
|
114274
114436
|
runMcpInit: () => runMcpInit
|
|
114275
114437
|
});
|
|
114276
114438
|
import { execFile } from "child_process";
|
|
114277
|
-
import { readFile as
|
|
114439
|
+
import { readFile as readFile7, writeFile as writeFile3, mkdir as mkdir2 } from "fs/promises";
|
|
114278
114440
|
import { createInterface } from "readline/promises";
|
|
114279
114441
|
import path3 from "path";
|
|
114280
114442
|
function buildServerEntry(opts) {
|
|
@@ -114379,7 +114541,7 @@ async function writeHarnessConfig(cwd, target, entry) {
|
|
|
114379
114541
|
const filePath = path3.join(cwd, target.file);
|
|
114380
114542
|
let root = {};
|
|
114381
114543
|
try {
|
|
114382
|
-
const existing = await
|
|
114544
|
+
const existing = await readFile7(filePath, "utf8");
|
|
114383
114545
|
const parsed = JSON.parse(existing);
|
|
114384
114546
|
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
114385
114547
|
return null;
|
|
@@ -114646,6 +114808,61 @@ async function runPreflight(opts) {
|
|
|
114646
114808
|
init_swap();
|
|
114647
114809
|
init_whoami();
|
|
114648
114810
|
|
|
114811
|
+
// src/commands/status.ts
|
|
114812
|
+
init_session();
|
|
114813
|
+
init_directory_state();
|
|
114814
|
+
init_colors();
|
|
114815
|
+
init_import();
|
|
114816
|
+
async function runStatus(opts) {
|
|
114817
|
+
const found = await findCredentials(opts.cwd);
|
|
114818
|
+
const organization = found?.creds.organization;
|
|
114819
|
+
if (found) {
|
|
114820
|
+
console.log(
|
|
114821
|
+
`Signed in as ${bold(found.creds.userEmail)} (${found.scope}) on ${found.creds.baseUrl}.`
|
|
114822
|
+
);
|
|
114823
|
+
console.log(
|
|
114824
|
+
` ${dim("Organization:")} ${organization ? `${organization.name}${organization.slug ? ` (${organization.slug})` : ""}` : "none chosen, following the web app (run `zoah organization switch`)"}`
|
|
114825
|
+
);
|
|
114826
|
+
} else {
|
|
114827
|
+
console.log("Not signed in. Run `zoah login` first.");
|
|
114828
|
+
}
|
|
114829
|
+
const state = await readDirectoryState(opts.cwd);
|
|
114830
|
+
console.log("");
|
|
114831
|
+
console.log(`${dim("This directory:")} ${describeState(state)}`);
|
|
114832
|
+
if (state.kind !== "new") {
|
|
114833
|
+
const url = buildDesignUrl(
|
|
114834
|
+
(found?.creds.baseUrl ?? opts.baseUrl).replace(/\/$/, ""),
|
|
114835
|
+
state.config
|
|
114836
|
+
);
|
|
114837
|
+
if (url) console.log(` ${dim("Project:")} ${url}`);
|
|
114838
|
+
if (state.manifest) {
|
|
114839
|
+
console.log(
|
|
114840
|
+
` ${dim("Package:")} ${state.manifest.name}@${state.manifest.version}`
|
|
114841
|
+
);
|
|
114842
|
+
}
|
|
114843
|
+
}
|
|
114844
|
+
const target = resolveImportTarget(state, organization);
|
|
114845
|
+
console.log(
|
|
114846
|
+
`${dim("Next import:")} ${describeTarget(target, organization)}`
|
|
114847
|
+
);
|
|
114848
|
+
const note = organizationNote(target, organization);
|
|
114849
|
+
if (note) console.log(dim(` ${note}`));
|
|
114850
|
+
console.log("");
|
|
114851
|
+
if (state.kind === "imported") {
|
|
114852
|
+
console.log(
|
|
114853
|
+
dim(
|
|
114854
|
+
"Nothing is swapped yet, so you can still move this directory: `zoah organization switch` to import into another organization, or `zoah import --new-project` for a new project here."
|
|
114855
|
+
)
|
|
114856
|
+
);
|
|
114857
|
+
} else if (state.kind === "swapped") {
|
|
114858
|
+
console.log(
|
|
114859
|
+
dim(
|
|
114860
|
+
"Swapped code renders this project's package, so the directory stays on it. `zoah import` adds new components; `zoah import --swap` also swaps them in."
|
|
114861
|
+
)
|
|
114862
|
+
);
|
|
114863
|
+
}
|
|
114864
|
+
}
|
|
114865
|
+
|
|
114649
114866
|
// src/app.tsx
|
|
114650
114867
|
init_flow();
|
|
114651
114868
|
init_errors();
|
|
@@ -114653,14 +114870,15 @@ init_components();
|
|
|
114653
114870
|
init_session();
|
|
114654
114871
|
init_client();
|
|
114655
114872
|
init_organization();
|
|
114873
|
+
init_directory_state();
|
|
114656
114874
|
init_local();
|
|
114657
114875
|
init_base_url();
|
|
114658
114876
|
init_issues_detail();
|
|
114659
114877
|
init_dist4();
|
|
114660
114878
|
init_screens();
|
|
114661
114879
|
init_components();
|
|
114662
|
-
import {
|
|
114663
|
-
import { readFile as
|
|
114880
|
+
import { Text as Text5 } from "ink";
|
|
114881
|
+
import { readFile as readFile6 } from "fs/promises";
|
|
114664
114882
|
import path2 from "path";
|
|
114665
114883
|
|
|
114666
114884
|
// src/ui/steps.tsx
|
|
@@ -114712,7 +114930,8 @@ var scan = async (carry) => {
|
|
|
114712
114930
|
branch: carry.branch,
|
|
114713
114931
|
debug: carry.debug
|
|
114714
114932
|
});
|
|
114715
|
-
|
|
114933
|
+
const upToDate = pipeline.payload.components.length === 0 && pipeline.alreadySwapped.length > 0 && pipeline.state.kind === "swapped" ? pipeline.state.manifest.name : void 0;
|
|
114934
|
+
if (pipeline.payload.components.length === 0 && !upToDate) {
|
|
114716
114935
|
throw new Error(
|
|
114717
114936
|
`No components were extractable from this project. Make sure your component files exist under \`${carry.scopePath}\` and use a supported styling approach.`
|
|
114718
114937
|
);
|
|
@@ -114722,7 +114941,7 @@ var scan = async (carry) => {
|
|
|
114722
114941
|
const { writeLastPayload: writeLastPayload2 } = await Promise.resolve().then(() => (init_local(), local_exports));
|
|
114723
114942
|
await writeLastPayload2(process.cwd(), pipeline.payload);
|
|
114724
114943
|
}
|
|
114725
|
-
return payloadToScanReport(pipeline);
|
|
114944
|
+
return { ...payloadToScanReport(pipeline), upToDate };
|
|
114726
114945
|
};
|
|
114727
114946
|
var scanLoader = (carry) => loader(
|
|
114728
114947
|
() => scan(carry),
|
|
@@ -114802,7 +115021,7 @@ async function flushIssueSnapshot() {
|
|
|
114802
115021
|
}
|
|
114803
115022
|
|
|
114804
115023
|
// src/app.tsx
|
|
114805
|
-
import { jsx as jsx4
|
|
115024
|
+
import { jsx as jsx4 } from "react/jsx-runtime";
|
|
114806
115025
|
var titleCase = (s5) => s5.replace(/[-_]+/g, " ").replace(/\b\w/g, (c3) => c3.toUpperCase()).trim();
|
|
114807
115026
|
function formatRelativeAge(isoTimestamp) {
|
|
114808
115027
|
const diffMs = Date.now() - new Date(isoTimestamp).getTime();
|
|
@@ -114823,7 +115042,7 @@ function formatRelativeAge(isoTimestamp) {
|
|
|
114823
115042
|
}
|
|
114824
115043
|
async function detectProjectName(cwd) {
|
|
114825
115044
|
try {
|
|
114826
|
-
const raw = await
|
|
115045
|
+
const raw = await readFile6(path2.join(cwd, "package.json"), "utf8");
|
|
114827
115046
|
const pkg = JSON.parse(raw);
|
|
114828
115047
|
if (typeof pkg.name === "string" && pkg.name) {
|
|
114829
115048
|
const bare = pkg.name.startsWith("@") ? pkg.name.split("/")[1] ?? pkg.name : pkg.name;
|
|
@@ -114833,15 +115052,6 @@ async function detectProjectName(cwd) {
|
|
|
114833
115052
|
}
|
|
114834
115053
|
return titleCase(path2.basename(cwd));
|
|
114835
115054
|
}
|
|
114836
|
-
async function packageInDeps(cwd, name) {
|
|
114837
|
-
try {
|
|
114838
|
-
const raw = await readFile5(path2.join(cwd, "package.json"), "utf8");
|
|
114839
|
-
const pkg = JSON.parse(raw);
|
|
114840
|
-
return Boolean(pkg.dependencies?.[name] ?? pkg.devDependencies?.[name]);
|
|
114841
|
-
} catch {
|
|
114842
|
-
return false;
|
|
114843
|
-
}
|
|
114844
|
-
}
|
|
114845
115055
|
var projectUrl = (baseUrl, config) => {
|
|
114846
115056
|
if (!config) return void 0;
|
|
114847
115057
|
if (!config.orgSlug || !config.projectSlug) return void 0;
|
|
@@ -114889,27 +115099,9 @@ async function runApp(opts = {}) {
|
|
|
114889
115099
|
version: manifest.version,
|
|
114890
115100
|
npmUrl: `https://npmjs.com/package/${manifest.name}`
|
|
114891
115101
|
} : void 0;
|
|
114892
|
-
const
|
|
115102
|
+
const state = await readDirectoryState(process.cwd());
|
|
115103
|
+
const plannedTarget = resolveImportTarget(state, creds?.organization);
|
|
114893
115104
|
const ui = createFlow();
|
|
114894
|
-
if (alreadySetUp && existingSync) {
|
|
114895
|
-
ui.log(
|
|
114896
|
-
/* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", gap: 1, marginY: 1, children: [
|
|
114897
|
-
/* @__PURE__ */ jsx4(Text5, { children: "Your project is already connected to Zoah." }),
|
|
114898
|
-
/* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", marginLeft: 2, children: [
|
|
114899
|
-
/* @__PURE__ */ jsxs4(Text5, { children: [
|
|
114900
|
-
/* @__PURE__ */ jsx4(Dim, { children: "Zoah " }),
|
|
114901
|
-
/* @__PURE__ */ jsx4(Text5, { color: "cyan", underline: true, children: existingSync.zoahUrl })
|
|
114902
|
-
] }),
|
|
114903
|
-
/* @__PURE__ */ jsxs4(Text5, { children: [
|
|
114904
|
-
/* @__PURE__ */ jsx4(Dim, { children: "Package " }),
|
|
114905
|
-
`${existingSync.packageName}@${existingSync.version}`
|
|
114906
|
-
] })
|
|
114907
|
-
] })
|
|
114908
|
-
] })
|
|
114909
|
-
);
|
|
114910
|
-
await ui.done();
|
|
114911
|
-
return;
|
|
114912
|
-
}
|
|
114913
115105
|
const carry = {
|
|
114914
115106
|
baseUrl,
|
|
114915
115107
|
scopePath,
|
|
@@ -114922,16 +115114,22 @@ async function runApp(opts = {}) {
|
|
|
114922
115114
|
userEmail: creds?.userEmail,
|
|
114923
115115
|
zoahUrl,
|
|
114924
115116
|
lastScanAge,
|
|
114925
|
-
sync: existingSync
|
|
115117
|
+
sync: existingSync,
|
|
115118
|
+
directory: describeState(state),
|
|
115119
|
+
next: describeTarget(plannedTarget, creds?.organization)
|
|
114926
115120
|
})
|
|
114927
115121
|
)) {
|
|
114928
115122
|
ui.log(/* @__PURE__ */ jsx4(Dim, { children: "Run `zoah` when you are ready." }));
|
|
114929
115123
|
return;
|
|
114930
115124
|
}
|
|
114931
|
-
const projectName = opts.projectName ?? await ui.run(askProjectName(detectedName));
|
|
115125
|
+
const projectName = opts.projectName ?? (plannedTarget.kind === "new" ? await ui.run(askProjectName(detectedName)) : void 0);
|
|
114932
115126
|
if (!creds) await ui.run(signIn(baseUrl));
|
|
114933
|
-
if (
|
|
114934
|
-
await ui.run(scanLoader(carry));
|
|
115127
|
+
if (state.kind !== "swapped") await ensureOrganization(ui, baseUrl);
|
|
115128
|
+
const scanReport = await ui.run(scanLoader(carry));
|
|
115129
|
+
if (scanReport.upToDate) {
|
|
115130
|
+
await flushIssueSnapshot();
|
|
115131
|
+
return;
|
|
115132
|
+
}
|
|
114935
115133
|
let syncResult;
|
|
114936
115134
|
try {
|
|
114937
115135
|
syncResult = await ui.run(syncLoader(projectName, carry));
|
|
@@ -115128,6 +115326,18 @@ async function main() {
|
|
|
115128
115326
|
fail(err);
|
|
115129
115327
|
}
|
|
115130
115328
|
});
|
|
115329
|
+
program.command("status").description(
|
|
115330
|
+
"Show this directory's Zoah project, whether it is swapped, and what `zoah import` will do."
|
|
115331
|
+
).action(async () => {
|
|
115332
|
+
try {
|
|
115333
|
+
await runStatus({
|
|
115334
|
+
cwd: process.cwd(),
|
|
115335
|
+
baseUrl: program.opts().baseUrl ?? DEFAULT_BASE_URL
|
|
115336
|
+
});
|
|
115337
|
+
} catch (err) {
|
|
115338
|
+
fail(err);
|
|
115339
|
+
}
|
|
115340
|
+
});
|
|
115131
115341
|
const mcp = program.command("mcp").description(
|
|
115132
115342
|
"Run the Zoah MCP server over stdio for coding agents. Run `zoah mcp init` to set up your harness; reuses `zoah login` credentials."
|
|
115133
115343
|
).option(
|
|
@@ -115194,6 +115404,10 @@ async function main() {
|
|
|
115194
115404
|
"--dry-run",
|
|
115195
115405
|
`Run the full local pipeline without calling the API or writing project state. Issues snapshot is still written to ${zoahPathDisplay.issues}. Equivalent to \`zoah preflight\`.`,
|
|
115196
115406
|
false
|
|
115407
|
+
).option(
|
|
115408
|
+
"--new-project",
|
|
115409
|
+
"Create a new project in the CLI's organization instead of updating the linked one. Not possible once the directory is swapped.",
|
|
115410
|
+
false
|
|
115197
115411
|
).action(
|
|
115198
115412
|
async (path4, options) => {
|
|
115199
115413
|
try {
|
|
@@ -115203,6 +115417,7 @@ async function main() {
|
|
|
115203
115417
|
scopePath: path4 ?? ".",
|
|
115204
115418
|
cwd: process.cwd(),
|
|
115205
115419
|
swap: options.swap,
|
|
115420
|
+
newProject: options.newProject,
|
|
115206
115421
|
projectName: g2.projectName,
|
|
115207
115422
|
branch: g2.branch,
|
|
115208
115423
|
debug: g2.debug ?? false,
|