@mondaydotcomorg/z2h-cli 0.15.0 → 0.15.2-feat-eitantsh-z2h-admin-panel-package-388aad6
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/commands/build.d.ts +0 -1
- package/dist/commands/build.d.ts.map +1 -1
- package/dist/commands/build.js +0 -3
- package/dist/commands/clean.d.ts +1 -4
- package/dist/commands/clean.d.ts.map +1 -1
- package/dist/commands/clean.js +1 -4
- package/dist/commands/create-workspace.d.ts +1 -4
- package/dist/commands/create-workspace.d.ts.map +1 -1
- package/dist/commands/create-workspace.js +1 -4
- package/dist/commands/create.d.ts +0 -1
- package/dist/commands/create.d.ts.map +1 -1
- package/dist/commands/create.js +0 -3
- package/dist/commands/delete.d.ts +0 -1
- package/dist/commands/delete.d.ts.map +1 -1
- package/dist/commands/delete.js +1 -4
- package/dist/commands/deploy.d.ts +0 -1
- package/dist/commands/deploy.d.ts.map +1 -1
- package/dist/commands/deploy.js +4 -7
- package/dist/commands/dev.d.ts +0 -1
- package/dist/commands/dev.d.ts.map +1 -1
- package/dist/commands/dev.js +0 -3
- package/dist/commands/doctor.d.ts +1 -4
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +2 -5
- package/dist/commands/edit.d.ts +1 -4
- package/dist/commands/edit.d.ts.map +1 -1
- package/dist/commands/edit.js +1 -4
- package/dist/commands/generate-z2h-token.d.ts +0 -1
- package/dist/commands/generate-z2h-token.d.ts.map +1 -1
- package/dist/commands/generate-z2h-token.js +0 -3
- package/dist/commands/grant.d.ts +1 -5
- package/dist/commands/grant.d.ts.map +1 -1
- package/dist/commands/grant.js +1 -10
- package/dist/commands/migrate.d.ts +0 -1
- package/dist/commands/migrate.d.ts.map +1 -1
- package/dist/commands/migrate.js +106 -4
- package/dist/commands/tag.d.ts +0 -1
- package/dist/commands/tag.d.ts.map +1 -1
- package/dist/commands/tag.js +1 -4
- package/dist/esm/commands/build.d.ts +0 -1
- package/dist/esm/commands/build.d.ts.map +1 -1
- package/dist/esm/commands/build.mjs +1 -4
- package/dist/esm/commands/clean.d.ts +1 -4
- package/dist/esm/commands/clean.d.ts.map +1 -1
- package/dist/esm/commands/clean.mjs +2 -5
- package/dist/esm/commands/create-workspace.d.ts +1 -4
- package/dist/esm/commands/create-workspace.d.ts.map +1 -1
- package/dist/esm/commands/create-workspace.mjs +2 -5
- package/dist/esm/commands/create.d.ts +0 -1
- package/dist/esm/commands/create.d.ts.map +1 -1
- package/dist/esm/commands/create.mjs +1 -4
- package/dist/esm/commands/delete.d.ts +0 -1
- package/dist/esm/commands/delete.d.ts.map +1 -1
- package/dist/esm/commands/delete.mjs +2 -5
- package/dist/esm/commands/deploy.d.ts +0 -1
- package/dist/esm/commands/deploy.d.ts.map +1 -1
- package/dist/esm/commands/deploy.mjs +5 -8
- package/dist/esm/commands/dev.d.ts +0 -1
- package/dist/esm/commands/dev.d.ts.map +1 -1
- package/dist/esm/commands/dev.mjs +1 -4
- package/dist/esm/commands/doctor.d.ts +1 -4
- package/dist/esm/commands/doctor.d.ts.map +1 -1
- package/dist/esm/commands/doctor.mjs +3 -6
- package/dist/esm/commands/edit.d.ts +1 -4
- package/dist/esm/commands/edit.d.ts.map +1 -1
- package/dist/esm/commands/edit.mjs +2 -5
- package/dist/esm/commands/generate-z2h-token.d.ts +0 -1
- package/dist/esm/commands/generate-z2h-token.d.ts.map +1 -1
- package/dist/esm/commands/generate-z2h-token.mjs +1 -4
- package/dist/esm/commands/grant.d.ts +1 -5
- package/dist/esm/commands/grant.d.ts.map +1 -1
- package/dist/esm/commands/grant.mjs +2 -11
- package/dist/esm/commands/migrate.d.ts +0 -1
- package/dist/esm/commands/migrate.d.ts.map +1 -1
- package/dist/esm/commands/migrate.mjs +101 -5
- package/dist/esm/commands/tag.d.ts +0 -1
- package/dist/esm/commands/tag.d.ts.map +1 -1
- package/dist/esm/commands/tag.mjs +2 -5
- package/dist/esm/index.mjs +20 -29
- package/dist/esm/util/tracker.d.ts.map +1 -1
- package/dist/esm/util/tracker.mjs +4 -1
- package/dist/esm/util/workspace.d.ts +3 -0
- package/dist/esm/util/workspace.d.ts.map +1 -1
- package/dist/esm/util/workspace.mjs +64 -2
- package/dist/index.js +19 -28
- package/dist/util/tracker.d.ts.map +1 -1
- package/dist/util/tracker.js +4 -1
- package/dist/util/workspace.d.ts +3 -0
- package/dist/util/workspace.d.ts.map +1 -1
- package/dist/util/workspace.js +65 -0
- package/package.json +1 -1
- package/src/commands/__tests__/doctor.test.ts +12 -5
- package/src/commands/build.ts +1 -6
- package/src/commands/clean.ts +2 -9
- package/src/commands/create-workspace.ts +2 -10
- package/src/commands/create.ts +1 -6
- package/src/commands/delete.ts +2 -7
- package/src/commands/deploy.ts +5 -10
- package/src/commands/dev.ts +1 -6
- package/src/commands/doctor.ts +3 -11
- package/src/commands/edit.ts +2 -10
- package/src/commands/generate-z2h-token.ts +1 -6
- package/src/commands/grant.ts +2 -16
- package/src/commands/migrate.ts +139 -6
- package/src/commands/tag.ts +2 -7
- package/src/index.ts +29 -41
- package/src/util/tracker.ts +6 -1
- package/src/util/workspace.ts +75 -1
- package/dist/esm/migrations/auto-migrate.d.ts +0 -2
- package/dist/esm/migrations/auto-migrate.d.ts.map +0 -1
- package/dist/esm/migrations/auto-migrate.mjs +0 -169
- package/dist/migrations/auto-migrate.d.ts +0 -2
- package/dist/migrations/auto-migrate.d.ts.map +0 -1
- package/dist/migrations/auto-migrate.js +0 -177
- package/src/migrations/auto-migrate.ts +0 -217
|
@@ -1,21 +1,13 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
2
|
import { readFile } from 'node:fs/promises';
|
|
3
3
|
import { ensureDir, writeFile, pathExists, readdir, copy } from 'fs-extra';
|
|
4
|
-
import { info, output
|
|
4
|
+
import { info, output } from '../util/logger';
|
|
5
5
|
import { getWorkspaceHome } from '../util/workspace';
|
|
6
6
|
import { getTemplatesDir } from '../util/templates';
|
|
7
7
|
import { runYarnInstall } from '../util/npm/install';
|
|
8
8
|
import { workspaceNpmrcContents, workspaceYarnrcContents } from '../util/npm/broker-config';
|
|
9
9
|
|
|
10
|
-
export
|
|
11
|
-
json?: boolean;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export async function createWorkspaceCommand(opts: CreateWorkspaceOptions = {}): Promise<void> {
|
|
15
|
-
if (opts.json) {
|
|
16
|
-
setOutputMode('json');
|
|
17
|
-
}
|
|
18
|
-
|
|
10
|
+
export async function createWorkspaceCommand(): Promise<void> {
|
|
19
11
|
const home = getWorkspaceHome();
|
|
20
12
|
const templatesDir = getTemplatesDir();
|
|
21
13
|
const wsTemplatesDir = path.join(templatesDir, 'workspace');
|
package/src/commands/create.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
2
|
import { readFile } from 'node:fs/promises';
|
|
3
3
|
import { ensureDir, pathExists, readdir, writeFile, copy } from 'fs-extra';
|
|
4
|
-
import { info, warn, output
|
|
4
|
+
import { info, warn, output } from '../util/logger';
|
|
5
5
|
import { assertWorkspace } from '../util/workspace';
|
|
6
6
|
import { getTemplatesDir, renderTemplate, APP_TEMPLATES, type AppTemplate } from '../util/templates';
|
|
7
7
|
import { APP_NAME_PATTERN } from '../constants';
|
|
@@ -19,7 +19,6 @@ export interface CreateOptions {
|
|
|
19
19
|
htmlFile?: string;
|
|
20
20
|
remote?: RemoteType;
|
|
21
21
|
repoUrl?: string;
|
|
22
|
-
json?: boolean;
|
|
23
22
|
}
|
|
24
23
|
|
|
25
24
|
// Names reserved by the host MF (mf-bigbrain-zth) for platform pages under
|
|
@@ -50,10 +49,6 @@ async function isDirEmpty(dir: string): Promise<boolean> {
|
|
|
50
49
|
}
|
|
51
50
|
|
|
52
51
|
export async function createCommand(appName: string, opts: CreateOptions = {}): Promise<void> {
|
|
53
|
-
if (opts.json) {
|
|
54
|
-
setOutputMode('json');
|
|
55
|
-
}
|
|
56
|
-
|
|
57
52
|
// Validate workspace.
|
|
58
53
|
const workspace = await assertWorkspace();
|
|
59
54
|
|
package/src/commands/delete.ts
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import { createInterface } from 'node:readline';
|
|
2
|
-
import { output, info,
|
|
2
|
+
import { output, info, getOutputMode } from '../util/logger';
|
|
3
3
|
import { getCwdAppName, cleanAppName, mfAppName } from '../util/app-name';
|
|
4
4
|
import { brokerBaseUrl, routingHeaders } from '../constants';
|
|
5
5
|
import { readZthAuth } from '../util/auth/auth-store';
|
|
6
6
|
|
|
7
7
|
export interface DeleteOptions {
|
|
8
8
|
yes?: boolean;
|
|
9
|
-
json?: boolean;
|
|
10
9
|
}
|
|
11
10
|
|
|
12
11
|
// Type-the-app-name confirmation. The caller must retype the de-scoped app
|
|
@@ -26,10 +25,6 @@ async function confirmByName(appSlug: string): Promise<boolean> {
|
|
|
26
25
|
|
|
27
26
|
// Should be run from the consumer app directory — uses process.cwd() to locate it.
|
|
28
27
|
export async function deleteCommand(opts: DeleteOptions = {}): Promise<void> {
|
|
29
|
-
if (opts.json) {
|
|
30
|
-
setOutputMode('json');
|
|
31
|
-
}
|
|
32
|
-
|
|
33
28
|
const cwdName = getCwdAppName();
|
|
34
29
|
if (!cwdName) {
|
|
35
30
|
throw new Error('Run this from inside a consumer app directory (the one with your package.json).');
|
|
@@ -39,7 +34,7 @@ export async function deleteCommand(opts: DeleteOptions = {}): Promise<void> {
|
|
|
39
34
|
|
|
40
35
|
// Confirmation. --json is always non-interactive, so it requires --yes.
|
|
41
36
|
if (!opts.yes) {
|
|
42
|
-
if (
|
|
37
|
+
if (getOutputMode() === 'json' || !process.stdin.isTTY) {
|
|
43
38
|
throw new Error('Refusing to delete without confirmation — pass --yes to delete non-interactively.');
|
|
44
39
|
}
|
|
45
40
|
if (!(await confirmByName(appSlug))) {
|
package/src/commands/deploy.ts
CHANGED
|
@@ -2,7 +2,7 @@ import path from 'node:path';
|
|
|
2
2
|
import os from 'node:os';
|
|
3
3
|
import { createInterface } from 'node:readline';
|
|
4
4
|
import { pathExists, readJson } from 'fs-extra';
|
|
5
|
-
import { info, warn, output,
|
|
5
|
+
import { info, warn, output, getOutputMode } from '../util/logger';
|
|
6
6
|
import { resolveConsumerPaths } from '../shadow/paths';
|
|
7
7
|
import { fetchAppTags, fetchTagCatalog, setAppTags } from '../util/tags';
|
|
8
8
|
import { type AssetManifestFile, type ManifestEntry } from '../util/manifest';
|
|
@@ -21,17 +21,12 @@ import { buildCommand } from './build';
|
|
|
21
21
|
|
|
22
22
|
export interface DeployOptions {
|
|
23
23
|
dryRun?: boolean;
|
|
24
|
-
json?: boolean;
|
|
25
24
|
remote?: RemoteType;
|
|
26
25
|
repoUrl?: string;
|
|
27
26
|
}
|
|
28
27
|
|
|
29
28
|
// Should be run from the consumer app directory — uses process.cwd() to locate it.
|
|
30
29
|
export async function deployCommand(opts: DeployOptions = {}): Promise<void> {
|
|
31
|
-
if (opts.json) {
|
|
32
|
-
setOutputMode('json');
|
|
33
|
-
}
|
|
34
|
-
|
|
35
30
|
const paths = resolveConsumerPaths(process.cwd());
|
|
36
31
|
const consumerPkg = (await readJson(paths.consumerPkg)) as { name?: string };
|
|
37
32
|
if (!consumerPkg.name) {
|
|
@@ -90,7 +85,7 @@ export async function deployCommand(opts: DeployOptions = {}): Promise<void> {
|
|
|
90
85
|
const url = `${BUCKET_READ_DNS_URL}/${keyPrefix}`;
|
|
91
86
|
|
|
92
87
|
info('building');
|
|
93
|
-
await buildCommand({
|
|
88
|
+
await buildCommand({ publicUrl: url });
|
|
94
89
|
|
|
95
90
|
if (!(await pathExists(paths.shadowBuild))) {
|
|
96
91
|
throw new Error(`No build output at ${paths.shadowBuild} after build step.`);
|
|
@@ -149,7 +144,7 @@ export async function deployCommand(opts: DeployOptions = {}): Promise<void> {
|
|
|
149
144
|
// The two are separate endpoints, so the CLI picks based on the version it
|
|
150
145
|
// was handed.
|
|
151
146
|
if (nextVersion === 1) {
|
|
152
|
-
const visibility = await resolveFirstDeployVisibility(appName
|
|
147
|
+
const visibility = await resolveFirstDeployVisibility(appName);
|
|
153
148
|
info(`registering app "${appName}" → v${nextVersion} (${visibility})`);
|
|
154
149
|
await registerApp(appName, token, nextVersion, entry, visibility, gitRemote);
|
|
155
150
|
} else {
|
|
@@ -262,8 +257,8 @@ async function updateApp(
|
|
|
262
257
|
// First deploy only: decide whether the app is born public or private. The
|
|
263
258
|
// choice is passed to the register endpoint (default private). Non-interactive
|
|
264
259
|
// runs (--json or no TTY) always default to private.
|
|
265
|
-
async function resolveFirstDeployVisibility(appName: string
|
|
266
|
-
if (json || !process.stdout.isTTY) {
|
|
260
|
+
async function resolveFirstDeployVisibility(appName: string): Promise<'public' | 'private'> {
|
|
261
|
+
if (getOutputMode() === 'json' || !process.stdout.isTTY) {
|
|
267
262
|
return 'private';
|
|
268
263
|
}
|
|
269
264
|
|
package/src/commands/dev.ts
CHANGED
|
@@ -3,7 +3,7 @@ import fs from 'node:fs';
|
|
|
3
3
|
import { readJson, writeFile } from 'fs-extra';
|
|
4
4
|
import { watch } from 'chokidar';
|
|
5
5
|
import { execa } from 'execa';
|
|
6
|
-
import { info, warn, errorLog, output
|
|
6
|
+
import { info, warn, errorLog, output } from '../util/logger';
|
|
7
7
|
import { prepareShadow } from '../shadow/prepare';
|
|
8
8
|
import { ensureConsumerPkg } from '../shadow/consumer-pkg';
|
|
9
9
|
import { syncShadow } from '../shadow/sync';
|
|
@@ -11,7 +11,6 @@ import { openInBrowser } from '../util/open-browser';
|
|
|
11
11
|
import type { ConsumerPkg } from '../types';
|
|
12
12
|
|
|
13
13
|
export interface DevOptions {
|
|
14
|
-
json?: boolean;
|
|
15
14
|
open?: boolean;
|
|
16
15
|
}
|
|
17
16
|
|
|
@@ -19,10 +18,6 @@ const TRIDENT_READY_PATTERN = /Server started at/i;
|
|
|
19
18
|
|
|
20
19
|
// Should be run from the consumer app directory — uses process.cwd() to locate it.
|
|
21
20
|
export async function devCommand(opts: DevOptions = {}): Promise<void> {
|
|
22
|
-
if (opts.json) {
|
|
23
|
-
setOutputMode('json');
|
|
24
|
-
}
|
|
25
|
-
|
|
26
21
|
const ctx = await prepareShadow();
|
|
27
22
|
const { port } = ctx;
|
|
28
23
|
const url = `https://bigbrain.me/bigbrain-vibe/${ctx.appName}?zth_local=${port}`;
|
package/src/commands/doctor.ts
CHANGED
|
@@ -6,7 +6,7 @@ import { execa } from 'execa';
|
|
|
6
6
|
import semver from 'semver';
|
|
7
7
|
import { pathExists, readJson } from 'fs-extra';
|
|
8
8
|
import pc from 'picocolors';
|
|
9
|
-
import {
|
|
9
|
+
import { output, getOutputMode } from '../util/logger';
|
|
10
10
|
import { isZ2hWorkspace, getWorkspaceHome } from '../util/workspace';
|
|
11
11
|
import { Z2H_AUTH_FILE, tryReadAuthTokenSync } from '../util/auth/auth-store';
|
|
12
12
|
import { brokerNpmRegistryUrl, routingHeaders } from '../constants';
|
|
@@ -26,10 +26,6 @@ const SSL_CERT_PATH = path.join(
|
|
|
26
26
|
'certificate.crt'
|
|
27
27
|
);
|
|
28
28
|
|
|
29
|
-
export interface DoctorOptions {
|
|
30
|
-
json?: boolean;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
29
|
type Status = 'ok' | 'warn' | 'fail';
|
|
34
30
|
|
|
35
31
|
interface CheckResult {
|
|
@@ -317,11 +313,7 @@ function renderCheck(c: CheckResult): void {
|
|
|
317
313
|
|
|
318
314
|
// ── command ───────────────────────────────────────────────────────────────────
|
|
319
315
|
|
|
320
|
-
export async function doctorCommand(
|
|
321
|
-
if (opts.json) {
|
|
322
|
-
setOutputMode('json');
|
|
323
|
-
}
|
|
324
|
-
|
|
316
|
+
export async function doctorCommand(): Promise<void> {
|
|
325
317
|
let pluginsJson: InstalledPluginsJson | null = null;
|
|
326
318
|
try {
|
|
327
319
|
if (await pathExists(CLAUDE_PLUGINS_JSON)) {
|
|
@@ -350,7 +342,7 @@ export async function doctorCommand(opts: DoctorOptions = {}): Promise<void> {
|
|
|
350
342
|
const allChecks = sections.flatMap(s => s.checks);
|
|
351
343
|
const issues = allChecks.filter(c => c.status !== 'ok');
|
|
352
344
|
|
|
353
|
-
if (
|
|
345
|
+
if (getOutputMode() === 'json') {
|
|
354
346
|
output('', {
|
|
355
347
|
ok: issues.filter(c => c.status === 'fail').length === 0,
|
|
356
348
|
checks: allChecks,
|
package/src/commands/edit.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
2
|
import { pathExists } from 'fs-extra';
|
|
3
|
-
import { info, warn, output
|
|
3
|
+
import { info, warn, output } from '../util/logger';
|
|
4
4
|
import { assertWorkspace } from '../util/workspace';
|
|
5
5
|
import { mfAppName } from '../util/app-name';
|
|
6
6
|
import { fetchApp } from '../util/broker/app';
|
|
@@ -9,15 +9,7 @@ import { cloneRepo, pullAndResolve } from '../util/git/repo';
|
|
|
9
9
|
import { runYarnInstall } from '../util/npm/install';
|
|
10
10
|
import { prepareShadow } from '../shadow/prepare';
|
|
11
11
|
|
|
12
|
-
export
|
|
13
|
-
json?: boolean;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export async function editCommand(appName: string, opts: EditOptions = {}): Promise<void> {
|
|
17
|
-
if (opts.json) {
|
|
18
|
-
setOutputMode('json');
|
|
19
|
-
}
|
|
20
|
-
|
|
12
|
+
export async function editCommand(appName: string): Promise<void> {
|
|
21
13
|
const workspace = await assertWorkspace();
|
|
22
14
|
const mfName = mfAppName(appName);
|
|
23
15
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import readline from 'node:readline/promises';
|
|
2
2
|
import { stdin, stdout } from 'node:process';
|
|
3
|
-
import { info, warn, output
|
|
3
|
+
import { info, warn, output } from '../util/logger';
|
|
4
4
|
import { writeZthAuth, validateJwtPattern } from '../util/auth/write-auth';
|
|
5
5
|
import { startLoopbackServer } from '../util/auth/loopback-server';
|
|
6
6
|
import { openInBrowser } from '../util/open-browser';
|
|
@@ -18,7 +18,6 @@ export interface GenerateZ2HTokenOptions {
|
|
|
18
18
|
noBrowser?: boolean;
|
|
19
19
|
/** Override the page URL — useful when pointing at staging. */
|
|
20
20
|
url?: string;
|
|
21
|
-
json?: boolean;
|
|
22
21
|
}
|
|
23
22
|
|
|
24
23
|
async function promptForToken(): Promise<string> {
|
|
@@ -76,10 +75,6 @@ async function runLoopbackFlow(pageUrl: string): Promise<string | null> {
|
|
|
76
75
|
}
|
|
77
76
|
|
|
78
77
|
export async function generateZ2HTokenCommand(opts: GenerateZ2HTokenOptions = {}): Promise<void> {
|
|
79
|
-
if (opts.json) {
|
|
80
|
-
setOutputMode('json');
|
|
81
|
-
}
|
|
82
|
-
|
|
83
78
|
const pageUrl = opts.url ?? process.env.Z2H_TOKEN_PAGE_URL ?? DEFAULT_TOKEN_PAGE_URL;
|
|
84
79
|
|
|
85
80
|
// --no-browser bypasses both auto-open and the loopback round-trip — the
|
package/src/commands/grant.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { output
|
|
1
|
+
import { output } from '../util/logger';
|
|
2
2
|
import { getCwdAppName, mfAppName } from '../util/app-name';
|
|
3
3
|
import { brokerBaseUrl, routingHeaders } from '../constants';
|
|
4
4
|
import { readZthAuth } from '../util/auth/auth-store';
|
|
@@ -6,7 +6,6 @@ import { readZthAuth } from '../util/auth/auth-store';
|
|
|
6
6
|
export interface GrantOptions {
|
|
7
7
|
public?: boolean;
|
|
8
8
|
level?: 'owner' | 'editor' | 'viewer';
|
|
9
|
-
json?: boolean;
|
|
10
9
|
}
|
|
11
10
|
|
|
12
11
|
async function postGrant(
|
|
@@ -26,9 +25,6 @@ async function postGrant(
|
|
|
26
25
|
}
|
|
27
26
|
|
|
28
27
|
export async function grantCommand(email: string | undefined, opts: GrantOptions): Promise<void> {
|
|
29
|
-
if (opts.json) {
|
|
30
|
-
setOutputMode('json');
|
|
31
|
-
}
|
|
32
28
|
if (!opts.public && !email) {
|
|
33
29
|
throw new Error('Specify what to grant — e.g. --public or provide an email');
|
|
34
30
|
}
|
|
@@ -59,9 +55,6 @@ export async function grantCommand(email: string | undefined, opts: GrantOptions
|
|
|
59
55
|
}
|
|
60
56
|
|
|
61
57
|
export async function revokeCommand(email: string | undefined, opts: GrantOptions): Promise<void> {
|
|
62
|
-
if (opts.json) {
|
|
63
|
-
setOutputMode('json');
|
|
64
|
-
}
|
|
65
58
|
if (!opts.public && !email) {
|
|
66
59
|
throw new Error('Specify what to revoke — e.g. --public or provide an email');
|
|
67
60
|
}
|
|
@@ -86,14 +79,7 @@ export async function revokeCommand(email: string | undefined, opts: GrantOption
|
|
|
86
79
|
output(msg, { ok: true, appName, revoked });
|
|
87
80
|
}
|
|
88
81
|
|
|
89
|
-
export
|
|
90
|
-
json?: boolean;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
export async function transferOwnerCommand(email: string | undefined, opts: TransferOwnerOptions): Promise<void> {
|
|
94
|
-
if (opts.json) {
|
|
95
|
-
setOutputMode('json');
|
|
96
|
-
}
|
|
82
|
+
export async function transferOwnerCommand(email: string | undefined): Promise<void> {
|
|
97
83
|
if (!email) {
|
|
98
84
|
throw new Error('Specify the new owner — e.g. z2h-cli transfer-owner someone@monday.com');
|
|
99
85
|
}
|
package/src/commands/migrate.ts
CHANGED
|
@@ -1,15 +1,148 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
1
|
+
import { createRequire } from 'node:module';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
import { pathExists, readJson, writeJson } from 'fs-extra';
|
|
5
|
+
import semver from 'semver';
|
|
6
|
+
import { errorLog, info, warn } from '../util/logger';
|
|
7
|
+
import { getWorkspaceHome, isZ2hWorkspace, ensureWorkspaceNx, runYarnInstall } from '../util/workspace';
|
|
8
|
+
|
|
9
|
+
const STATE_FILE = '.z2h-migrations-state.json';
|
|
10
|
+
|
|
11
|
+
interface MigrationState {
|
|
12
|
+
lastMigratedVersion: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
interface MigrationEntry {
|
|
16
|
+
version: string;
|
|
17
|
+
description: string;
|
|
18
|
+
migrate: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
interface MigrationsJson {
|
|
22
|
+
migrations: Record<string, MigrationEntry>;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// ─── Helpers ───
|
|
26
|
+
|
|
27
|
+
async function readMigrationState(workspaceHome: string): Promise<MigrationState | null> {
|
|
28
|
+
const statePath = path.join(workspaceHome, STATE_FILE);
|
|
29
|
+
if (!(await pathExists(statePath))) {
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
try {
|
|
33
|
+
return (await readJson(statePath)) as MigrationState;
|
|
34
|
+
} catch {
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
async function writeMigrationState(workspaceHome: string, state: MigrationState): Promise<void> {
|
|
40
|
+
const statePath = path.join(workspaceHome, STATE_FILE);
|
|
41
|
+
await writeJson(statePath, state, { spaces: 2 });
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// ─── Main ───
|
|
3
45
|
|
|
4
46
|
export interface MigrateOptions {
|
|
5
47
|
dryRun?: boolean;
|
|
6
|
-
json?: boolean;
|
|
7
48
|
}
|
|
8
49
|
|
|
9
50
|
export async function migrateCommand(cliVersion: string, opts: MigrateOptions = {}): Promise<void> {
|
|
10
|
-
|
|
11
|
-
|
|
51
|
+
const workspaceHome = getWorkspaceHome();
|
|
52
|
+
if (!(await isZ2hWorkspace(workspaceHome))) {
|
|
53
|
+
warn('no Z2H workspace found');
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const state = await readMigrationState(workspaceHome);
|
|
58
|
+
const lastVersion = state?.lastMigratedVersion ?? '0.0.0';
|
|
59
|
+
|
|
60
|
+
if (!semver.gt(cliVersion, lastVersion)) {
|
|
61
|
+
info('workspace is up to date — no migrations pending');
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
info(`migrating workspace from v${lastVersion} → v${cliVersion}...`);
|
|
66
|
+
|
|
67
|
+
// migrations.json is at the package root — two dirs up from dist/migrations/
|
|
68
|
+
const thisDir = path.dirname(fileURLToPath(import.meta.url));
|
|
69
|
+
const migrationsJsonPath = path.resolve(thisDir, '..', '..', 'migrations.json');
|
|
70
|
+
|
|
71
|
+
if (!(await pathExists(migrationsJsonPath))) {
|
|
72
|
+
warn('migrations.json not found — skipping migrations');
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const migrationsJson = (await readJson(migrationsJsonPath)) as MigrationsJson;
|
|
77
|
+
|
|
78
|
+
// Filter to pending migrations (version > lastVersion AND <= cliVersion).
|
|
79
|
+
// CONVENTION: a migration's `version` field must equal the CLI release it
|
|
80
|
+
// ships with (not the feature branch version). This ensures the `gt` check
|
|
81
|
+
// always catches a migration on the exact upgrade that introduces it.
|
|
82
|
+
const pending = Object.entries(migrationsJson.migrations)
|
|
83
|
+
.filter(([, entry]) => semver.gt(entry.version, lastVersion) && semver.lte(entry.version, cliVersion))
|
|
84
|
+
.sort(([, a], [, b]) => semver.compare(a.version, b.version));
|
|
85
|
+
|
|
86
|
+
if (opts.dryRun) {
|
|
87
|
+
info(`${pending.length} pending migration(s) (dry-run — no changes will be applied):`);
|
|
88
|
+
for (const [, entry] of pending) {
|
|
89
|
+
info(` - ${entry.description} (v${entry.version})`);
|
|
90
|
+
}
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (pending.length === 0) {
|
|
95
|
+
await writeMigrationState(workspaceHome, { lastMigratedVersion: cliVersion });
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const nxReady = await ensureWorkspaceNx(workspaceHome);
|
|
100
|
+
if (!nxReady) {
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
info(`applying ${pending.length} workspace migration(s)...`);
|
|
105
|
+
|
|
106
|
+
// Resolve NX from the workspace's node_modules (not from CLI's own deps)
|
|
107
|
+
const wsRequire = createRequire(path.join(workspaceHome, 'package.json'));
|
|
108
|
+
const { FsTree, flushChanges } = wsRequire('nx/src/generators/tree') as {
|
|
109
|
+
FsTree: new (root: string, isVerbose: boolean) => import('@nx/devkit').Tree & {
|
|
110
|
+
listChanges(): { type: string; path: string }[];
|
|
111
|
+
};
|
|
112
|
+
flushChanges: (root: string, changes: { type: string; path: string; content?: Buffer | null }[]) => void;
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
let needsInstall = false;
|
|
116
|
+
|
|
117
|
+
for (const [name, entry] of pending) {
|
|
118
|
+
const tree = new FsTree(workspaceHome, false);
|
|
119
|
+
try {
|
|
120
|
+
const factoryPath = path.resolve(path.dirname(migrationsJsonPath), entry.migrate);
|
|
121
|
+
const mod = require(factoryPath);
|
|
122
|
+
const fn = mod.default || mod;
|
|
123
|
+
fn(tree);
|
|
124
|
+
|
|
125
|
+
const changes = tree.listChanges();
|
|
126
|
+
if (changes.length > 0) {
|
|
127
|
+
if (changes.some(c => c.path.endsWith('package.json'))) {
|
|
128
|
+
needsInstall = true;
|
|
129
|
+
}
|
|
130
|
+
flushChanges(workspaceHome, changes);
|
|
131
|
+
info(` ✓ ${entry.description}`);
|
|
132
|
+
} else {
|
|
133
|
+
info(` ○ ${entry.description} (no changes needed)`);
|
|
134
|
+
}
|
|
135
|
+
} catch (err) {
|
|
136
|
+
const errorMessage = `migration "${name}" failed: ${(err as Error).message}`;
|
|
137
|
+
errorLog(`${errorMessage}\nSkipping remaining migrations — run "z2h-cli migrate" to retry.`);
|
|
138
|
+
throw new Error(errorMessage);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
if (needsInstall) {
|
|
143
|
+
await runYarnInstall(workspaceHome, 'package.json changed');
|
|
12
144
|
}
|
|
13
145
|
|
|
14
|
-
await
|
|
146
|
+
await writeMigrationState(workspaceHome, { lastMigratedVersion: cliVersion });
|
|
147
|
+
info('workspace migrations complete.');
|
|
15
148
|
}
|
package/src/commands/tag.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { stdin, stdout } from 'node:process';
|
|
|
3
3
|
import { readJson } from 'fs-extra';
|
|
4
4
|
import { resolveConsumerPaths } from '../shadow/paths';
|
|
5
5
|
import { mfAppName } from '../util/app-name';
|
|
6
|
-
import { info, output,
|
|
6
|
+
import { info, output, getOutputMode } from '../util/logger';
|
|
7
7
|
import {
|
|
8
8
|
fetchAppTags,
|
|
9
9
|
fetchTagCatalog,
|
|
@@ -17,7 +17,6 @@ import {
|
|
|
17
17
|
export interface TagOptions {
|
|
18
18
|
/** Repeatable `--tag` — sets the full tag set non-interactively. */
|
|
19
19
|
tag?: string[];
|
|
20
|
-
json?: boolean;
|
|
21
20
|
}
|
|
22
21
|
|
|
23
22
|
/** Render an app's tags as `name (Type), ...` — or `(none)`. */
|
|
@@ -100,10 +99,6 @@ export async function promptForTags(appSlug: string, catalog: CatalogEntry[], cu
|
|
|
100
99
|
}
|
|
101
100
|
|
|
102
101
|
export async function tagCommand(appArg: string | undefined, opts: TagOptions): Promise<void> {
|
|
103
|
-
if (opts.json) {
|
|
104
|
-
setOutputMode('json');
|
|
105
|
-
}
|
|
106
|
-
|
|
107
102
|
const appSlug = await resolveAppSlug(appArg);
|
|
108
103
|
|
|
109
104
|
// Non-interactive write: `--tag` flags set the full set directly.
|
|
@@ -118,7 +113,7 @@ export async function tagCommand(appArg: string | undefined, opts: TagOptions):
|
|
|
118
113
|
// Read-only listing: agents (`--json`) and any non-TTY caller get the catalog
|
|
119
114
|
// + current tags without a prompt — then they set tags via `--tag`. This also
|
|
120
115
|
// avoids hanging on `readline` when no human is attached to stdin.
|
|
121
|
-
if (
|
|
116
|
+
if (getOutputMode() === 'json' || !process.stdin.isTTY) {
|
|
122
117
|
output(
|
|
123
118
|
`[z2h-cli] "${appSlug}"\n catalog: ${
|
|
124
119
|
catalog.map(t => `${t.name} (${TAG_TYPE_LABELS[t.type]})`).join(', ') || '(none)'
|