@constructive-io/cli 5.1.24 → 5.2.1

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/commands.js CHANGED
@@ -5,16 +5,14 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.commands = void 0;
7
7
  const find_and_require_package_json_1 = require("find-and-require-package-json");
8
- const pgpm_1 = require("pgpm");
9
8
  const codegen_1 = __importDefault(require("./commands/codegen"));
10
9
  const explorer_1 = __importDefault(require("./commands/explorer"));
11
10
  const get_graphql_schema_1 = __importDefault(require("./commands/get-graphql-schema"));
12
11
  const server_1 = __importDefault(require("./commands/server"));
13
12
  const utils_1 = require("./utils");
14
- const createCommandMap = (skipPgTeardown = false) => {
15
- const pgpmCommands = (0, pgpm_1.createPgpmCommandMap)(skipPgTeardown);
13
+ const update_check_1 = require("./utils/update-check");
14
+ const createCommandMap = () => {
16
15
  return {
17
- ...pgpmCommands,
18
16
  server: server_1.default,
19
17
  explorer: explorer_1.default,
20
18
  'get-graphql-schema': get_graphql_schema_1.default,
@@ -26,7 +24,7 @@ const commands = async (argv, prompter, options) => {
26
24
  // Run update check early so it shows on help/version paths too
27
25
  try {
28
26
  const pkg = (0, find_and_require_package_json_1.findAndRequirePackageJson)(__dirname);
29
- await (0, pgpm_1.checkForUpdates)({
27
+ await (0, update_check_1.checkForUpdates)({
30
28
  command: command || 'help',
31
29
  pkgName: pkg.name,
32
30
  pkgVersion: pkg.version,
@@ -53,12 +51,7 @@ const commands = async (argv, prompter, options) => {
53
51
  console.log(utils_1.usageText);
54
52
  process.exit(0);
55
53
  }
56
- // Command-specific help for init
57
- if (command === 'init' && (argv.help || argv.h)) {
58
- console.log((0, pgpm_1.createInitUsageText)('constructive', 'Constructive'));
59
- process.exit(0);
60
- }
61
- const commandMap = createCommandMap(options?.skipPgTeardown);
54
+ const commandMap = createCommandMap();
62
55
  // Prompt if no command provided
63
56
  if (!command) {
64
57
  const answer = await prompter.prompt(argv, [
package/esm/commands.js CHANGED
@@ -1,14 +1,12 @@
1
1
  import { findAndRequirePackageJson } from 'find-and-require-package-json';
2
- import { checkForUpdates, createInitUsageText, createPgpmCommandMap } from 'pgpm';
3
2
  import codegen from './commands/codegen';
4
3
  import explorer from './commands/explorer';
5
4
  import getGraphqlSchema from './commands/get-graphql-schema';
6
5
  import server from './commands/server';
7
6
  import { cliExitWithError, extractFirst, usageText } from './utils';
8
- const createCommandMap = (skipPgTeardown = false) => {
9
- const pgpmCommands = createPgpmCommandMap(skipPgTeardown);
7
+ import { checkForUpdates } from './utils/update-check';
8
+ const createCommandMap = () => {
10
9
  return {
11
- ...pgpmCommands,
12
10
  server,
13
11
  explorer,
14
12
  'get-graphql-schema': getGraphqlSchema,
@@ -47,12 +45,7 @@ export const commands = async (argv, prompter, options) => {
47
45
  console.log(usageText);
48
46
  process.exit(0);
49
47
  }
50
- // Command-specific help for init
51
- if (command === 'init' && (argv.help || argv.h)) {
52
- console.log(createInitUsageText('constructive', 'Constructive'));
53
- process.exit(0);
54
- }
55
- const commandMap = createCommandMap(options?.skipPgTeardown);
48
+ const commandMap = createCommandMap();
56
49
  // Prompt if no command provided
57
50
  if (!command) {
58
51
  const answer = await prompter.prompt(argv, [
@@ -0,0 +1,8 @@
1
+ export const extractFirst = (argv) => {
2
+ const first = argv._?.[0];
3
+ const newArgv = {
4
+ ...argv,
5
+ _: argv._?.slice(1) ?? []
6
+ };
7
+ return { first, newArgv };
8
+ };
@@ -0,0 +1,31 @@
1
+ import { Logger } from '@pgpmjs/logger';
2
+ import { PgpmError } from '@pgpmjs/types';
3
+ const log = new Logger('cli');
4
+ /**
5
+ * CLI error utility that logs error information and exits with code 1.
6
+ * Provides consistent error handling and user experience across all CLI commands.
7
+ */
8
+ export const cliExitWithError = async (error, context) => {
9
+ if (error instanceof PgpmError) {
10
+ log.error(`Error: ${error.message}`);
11
+ if (error.context && Object.keys(error.context).length > 0) {
12
+ log.debug('Error context:', error.context);
13
+ }
14
+ if (context) {
15
+ log.debug('Additional context:', context);
16
+ }
17
+ }
18
+ else if (error instanceof Error) {
19
+ log.error(`Error: ${error.message}`);
20
+ if (context) {
21
+ log.debug('Context:', context);
22
+ }
23
+ }
24
+ else if (typeof error === 'string') {
25
+ log.error(`Error: ${error}`);
26
+ if (context) {
27
+ log.debug('Context:', context);
28
+ }
29
+ }
30
+ process.exit(1);
31
+ };
@@ -2,63 +2,33 @@ export const usageText = `
2
2
  Usage: cnc <command> [options]
3
3
  constructive <command> [options]
4
4
 
5
- Core Database Operations:
6
- add Add database changes to plans and create SQL files
7
- deploy Deploy database changes and migrations
8
- verify Verify database state and migrations
9
- revert Revert database changes and migrations
5
+ Constructive CLI - API Server and Development Tools
10
6
 
11
- Project Management:
12
- init Initialize pgpm workspace or module
13
- extension Manage module dependencies
14
- plan Generate module deployment plans
15
- package Package module for distribution
16
- update Update CLI/pgpm (installs pgpm by default)
17
- cache Manage cached templates (clean)
18
- upgrade-modules Upgrade installed pgpm modules to latest versions
19
-
20
- Development Tools:
7
+ GraphQL Server:
21
8
  server Start a GraphQL server
22
9
  explorer Launch GraphiQL explorer interface
23
- docker Manage PostgreSQL Docker containers (start/stop)
24
- export Export database migrations from existing databases
25
- env Display environment configuration
26
10
 
27
11
  Code Generation:
28
12
  codegen Generate TypeScript types and SDK from GraphQL schema
29
13
  get-graphql-schema Fetch or build GraphQL schema SDL
30
14
 
31
- Database Administration:
32
- kill Terminate database connections and optionally drop databases
33
- install Install pgpm modules
34
- tag Add tags to changes for versioning
35
- clear Clear database state
36
- remove Remove database changes
37
- analyze Analyze database structure
38
- rename Rename database changes
39
- admin-users Manage admin users
40
-
41
- Testing:
42
- test-packages Run integration tests on all workspace packages
43
-
44
- Migration Tools:
45
- migrate Migration management subcommands
46
- init Initialize migration tracking
47
- status Show migration status
48
- list List all changes
49
- deps Show change dependencies
50
-
51
15
  Global Options:
52
16
  -h, --help Display this help information
53
17
  -v, --version Display version information
54
18
  --cwd <directory> Working directory (default: current directory)
55
19
 
56
20
  Individual Command Help:
57
- constructive <command> --help Display detailed help for specific command
58
- constructive <command> -h Display detailed help for specific command
21
+ cnc <command> --help Display detailed help for specific command
22
+ cnc <command> -h Display detailed help for specific command
59
23
 
60
24
  Examples:
61
- cnc deploy --help Show deploy command options
62
- cnc server --port 8080 Start server on port 8080
63
- cnc init workspace Initialize new workspace
25
+ cnc server Start GraphQL server
26
+ cnc server --port 8080 Start server on custom port
27
+ cnc explorer Launch GraphiQL explorer
28
+ cnc codegen --schema schema.graphql Generate types from schema
29
+ cnc get-graphql-schema --out schema.graphql Export schema SDL
30
+
31
+ Database Operations:
32
+ For database migrations, packages, and deployment, use pgpm:
33
+ https://pgpm.io
64
34
  `;
@@ -1,3 +1,3 @@
1
- export { extractFirst } from 'pgpm';
2
- export { cliExitWithError } from 'pgpm';
1
+ export { extractFirst } from './argv';
2
+ export { cliExitWithError } from './cli-error';
3
3
  export { usageText } from './display';
@@ -0,0 +1,107 @@
1
+ import { findAndRequirePackageJson } from 'find-and-require-package-json';
2
+ import { Logger } from '@pgpmjs/logger';
3
+ import fs from 'fs';
4
+ import path from 'path';
5
+ import os from 'os';
6
+ const log = new Logger('update-check');
7
+ const UPDATE_CHECK_TTL_MS = 7 * 24 * 60 * 60 * 1000; // 1 week
8
+ const shouldSkip = (command) => {
9
+ if (process.env.PGPM_SKIP_UPDATE_CHECK)
10
+ return true;
11
+ if (process.env.CI === 'true')
12
+ return true;
13
+ return false;
14
+ };
15
+ function getConfigPath(toolName, key) {
16
+ const configDir = path.join(os.homedir(), `.${toolName}`);
17
+ return path.join(configDir, `${key}.json`);
18
+ }
19
+ function readConfig(toolName, key) {
20
+ try {
21
+ const configPath = getConfigPath(toolName, key);
22
+ if (!fs.existsSync(configPath))
23
+ return null;
24
+ const content = fs.readFileSync(configPath, 'utf8');
25
+ return JSON.parse(content);
26
+ }
27
+ catch {
28
+ return null;
29
+ }
30
+ }
31
+ function writeConfig(toolName, key, config) {
32
+ try {
33
+ const configPath = getConfigPath(toolName, key);
34
+ const configDir = path.dirname(configPath);
35
+ if (!fs.existsSync(configDir)) {
36
+ fs.mkdirSync(configDir, { recursive: true });
37
+ }
38
+ fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
39
+ }
40
+ catch {
41
+ // Ignore write errors
42
+ }
43
+ }
44
+ async function fetchLatestVersion(pkgName) {
45
+ try {
46
+ const response = await fetch(`https://registry.npmjs.org/${pkgName}/latest`);
47
+ if (!response.ok)
48
+ return null;
49
+ const data = await response.json();
50
+ return data.version || null;
51
+ }
52
+ catch {
53
+ return null;
54
+ }
55
+ }
56
+ function compareVersions(current, latest) {
57
+ const currentParts = current.replace(/^v/, '').split('.').map(Number);
58
+ const latestParts = latest.replace(/^v/, '').split('.').map(Number);
59
+ for (let i = 0; i < Math.max(currentParts.length, latestParts.length); i++) {
60
+ const c = currentParts[i] || 0;
61
+ const l = latestParts[i] || 0;
62
+ if (c < l)
63
+ return -1;
64
+ if (c > l)
65
+ return 1;
66
+ }
67
+ return 0;
68
+ }
69
+ export async function checkForUpdates(options = {}) {
70
+ const { pkgName = '@constructive-io/cli', pkgVersion = findAndRequirePackageJson(__dirname).version, command, now = Date.now(), key = 'update-check', toolName = 'constructive' } = options;
71
+ if (shouldSkip(command)) {
72
+ return null;
73
+ }
74
+ try {
75
+ const existing = readConfig(toolName, key);
76
+ let latestKnownVersion = existing?.latestKnownVersion ?? pkgVersion;
77
+ const needsCheck = !existing?.lastCheckedAt || (now - existing.lastCheckedAt) > UPDATE_CHECK_TTL_MS;
78
+ if (needsCheck) {
79
+ const fetched = await fetchLatestVersion(pkgName);
80
+ if (fetched) {
81
+ latestKnownVersion = fetched;
82
+ }
83
+ writeConfig(toolName, key, {
84
+ lastCheckedAt: now,
85
+ latestKnownVersion
86
+ });
87
+ }
88
+ const comparison = compareVersions(pkgVersion, latestKnownVersion);
89
+ const isOutdated = comparison < 0;
90
+ if (isOutdated) {
91
+ const updateInstruction = options.updateCommand ?? `Run npm i -g ${pkgName}@latest to upgrade.`;
92
+ log.warn(`A new version of ${pkgName} is available (current ${pkgVersion}, latest ${latestKnownVersion}). ${updateInstruction}`);
93
+ writeConfig(toolName, key, {
94
+ lastCheckedAt: now,
95
+ latestKnownVersion
96
+ });
97
+ }
98
+ return {
99
+ lastCheckedAt: now,
100
+ latestKnownVersion
101
+ };
102
+ }
103
+ catch (error) {
104
+ log.debug('Update check skipped due to error:', error);
105
+ return null;
106
+ }
107
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@constructive-io/cli",
3
- "version": "5.1.24",
3
+ "version": "5.2.1",
4
4
  "author": "Constructive <developers@constructive.io>",
5
5
  "description": "Constructive CLI",
6
6
  "main": "index.js",
@@ -46,21 +46,21 @@
46
46
  "ts-node": "^10.9.2"
47
47
  },
48
48
  "dependencies": {
49
- "@constructive-io/graphql-codegen": "^2.17.32",
50
- "@constructive-io/graphql-env": "^2.8.10",
51
- "@constructive-io/graphql-explorer": "^2.10.25",
52
- "@constructive-io/graphql-server": "^2.10.25",
53
- "@pgpmjs/core": "^4.1.1",
49
+ "@constructive-io/graphql-codegen": "^2.17.34",
50
+ "@constructive-io/graphql-env": "^2.8.11",
51
+ "@constructive-io/graphql-explorer": "^2.10.27",
52
+ "@constructive-io/graphql-server": "^2.10.27",
53
+ "@pgpmjs/core": "^4.2.0",
54
54
  "@pgpmjs/logger": "^1.3.5",
55
- "@pgpmjs/server-utils": "^2.8.10",
56
- "@pgpmjs/types": "^2.12.7",
55
+ "@pgpmjs/server-utils": "^2.8.11",
56
+ "@pgpmjs/types": "^2.12.8",
57
57
  "find-and-require-package-json": "^0.8.2",
58
58
  "inquirerer": "^2.4.0",
59
59
  "js-yaml": "^4.1.0",
60
60
  "minimist": "^1.2.8",
61
- "pg-cache": "^1.6.10",
61
+ "pg-cache": "^1.6.11",
62
62
  "pg-env": "^1.2.4",
63
- "pgpm": "^2.2.1",
63
+ "pgpm": "^2.4.0",
64
64
  "shelljs": "^0.10.0",
65
65
  "yanse": "^0.1.8"
66
66
  },
@@ -75,5 +75,5 @@
75
75
  "postgres",
76
76
  "graphile"
77
77
  ],
78
- "gitHead": "e3d01915223e3d87d263606bc4086e3e88183cab"
78
+ "gitHead": "9b68e2d19937ad4e2a81a5de110a197a8572e3d9"
79
79
  }
@@ -0,0 +1,8 @@
1
+ import { ParsedArgs } from 'minimist';
2
+ export declare const extractFirst: (argv: Partial<ParsedArgs>) => {
3
+ first: string;
4
+ newArgv: {
5
+ _: string[];
6
+ "--"?: string[] | undefined;
7
+ };
8
+ };
package/utils/argv.js ADDED
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.extractFirst = void 0;
4
+ const extractFirst = (argv) => {
5
+ const first = argv._?.[0];
6
+ const newArgv = {
7
+ ...argv,
8
+ _: argv._?.slice(1) ?? []
9
+ };
10
+ return { first, newArgv };
11
+ };
12
+ exports.extractFirst = extractFirst;
@@ -0,0 +1,6 @@
1
+ import { PgpmError } from '@pgpmjs/types';
2
+ /**
3
+ * CLI error utility that logs error information and exits with code 1.
4
+ * Provides consistent error handling and user experience across all CLI commands.
5
+ */
6
+ export declare const cliExitWithError: (error: PgpmError | Error | string, context?: Record<string, any>) => Promise<never>;
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.cliExitWithError = void 0;
4
+ const logger_1 = require("@pgpmjs/logger");
5
+ const types_1 = require("@pgpmjs/types");
6
+ const log = new logger_1.Logger('cli');
7
+ /**
8
+ * CLI error utility that logs error information and exits with code 1.
9
+ * Provides consistent error handling and user experience across all CLI commands.
10
+ */
11
+ const cliExitWithError = async (error, context) => {
12
+ if (error instanceof types_1.PgpmError) {
13
+ log.error(`Error: ${error.message}`);
14
+ if (error.context && Object.keys(error.context).length > 0) {
15
+ log.debug('Error context:', error.context);
16
+ }
17
+ if (context) {
18
+ log.debug('Additional context:', context);
19
+ }
20
+ }
21
+ else if (error instanceof Error) {
22
+ log.error(`Error: ${error.message}`);
23
+ if (context) {
24
+ log.debug('Context:', context);
25
+ }
26
+ }
27
+ else if (typeof error === 'string') {
28
+ log.error(`Error: ${error}`);
29
+ if (context) {
30
+ log.debug('Context:', context);
31
+ }
32
+ }
33
+ process.exit(1);
34
+ };
35
+ exports.cliExitWithError = cliExitWithError;
@@ -1 +1 @@
1
- export declare const usageText = "\n Usage: cnc <command> [options]\n constructive <command> [options]\n\n Core Database Operations:\n add Add database changes to plans and create SQL files\n deploy Deploy database changes and migrations\n verify Verify database state and migrations\n revert Revert database changes and migrations\n\n Project Management:\n init Initialize pgpm workspace or module\n extension Manage module dependencies\n plan Generate module deployment plans\n package Package module for distribution\n update Update CLI/pgpm (installs pgpm by default)\n cache Manage cached templates (clean)\n upgrade-modules Upgrade installed pgpm modules to latest versions\n\n Development Tools:\n server Start a GraphQL server\n explorer Launch GraphiQL explorer interface\n docker Manage PostgreSQL Docker containers (start/stop)\n export Export database migrations from existing databases\n env Display environment configuration\n\n Code Generation:\n codegen Generate TypeScript types and SDK from GraphQL schema\n get-graphql-schema Fetch or build GraphQL schema SDL\n\n Database Administration:\n kill Terminate database connections and optionally drop databases\n install Install pgpm modules\n tag Add tags to changes for versioning\n clear Clear database state\n remove Remove database changes\n analyze Analyze database structure\n rename Rename database changes\n admin-users Manage admin users\n\n Testing:\n test-packages Run integration tests on all workspace packages\n\n Migration Tools:\n migrate Migration management subcommands\n init Initialize migration tracking\n status Show migration status\n list List all changes\n deps Show change dependencies\n\n Global Options:\n -h, --help Display this help information\n -v, --version Display version information\n --cwd <directory> Working directory (default: current directory)\n\n Individual Command Help:\n constructive <command> --help Display detailed help for specific command\n constructive <command> -h Display detailed help for specific command\n\n Examples:\n cnc deploy --help Show deploy command options\n cnc server --port 8080 Start server on port 8080\n cnc init workspace Initialize new workspace\n ";
1
+ export declare const usageText = "\n Usage: cnc <command> [options]\n constructive <command> [options]\n\n Constructive CLI - API Server and Development Tools\n\n GraphQL Server:\n server Start a GraphQL server\n explorer Launch GraphiQL explorer interface\n\n Code Generation:\n codegen Generate TypeScript types and SDK from GraphQL schema\n get-graphql-schema Fetch or build GraphQL schema SDL\n\n Global Options:\n -h, --help Display this help information\n -v, --version Display version information\n --cwd <directory> Working directory (default: current directory)\n\n Individual Command Help:\n cnc <command> --help Display detailed help for specific command\n cnc <command> -h Display detailed help for specific command\n\n Examples:\n cnc server Start GraphQL server\n cnc server --port 8080 Start server on custom port\n cnc explorer Launch GraphiQL explorer\n cnc codegen --schema schema.graphql Generate types from schema\n cnc get-graphql-schema --out schema.graphql Export schema SDL\n\n Database Operations:\n For database migrations, packages, and deployment, use pgpm:\n https://pgpm.io\n ";
package/utils/display.js CHANGED
@@ -5,63 +5,33 @@ exports.usageText = `
5
5
  Usage: cnc <command> [options]
6
6
  constructive <command> [options]
7
7
 
8
- Core Database Operations:
9
- add Add database changes to plans and create SQL files
10
- deploy Deploy database changes and migrations
11
- verify Verify database state and migrations
12
- revert Revert database changes and migrations
8
+ Constructive CLI - API Server and Development Tools
13
9
 
14
- Project Management:
15
- init Initialize pgpm workspace or module
16
- extension Manage module dependencies
17
- plan Generate module deployment plans
18
- package Package module for distribution
19
- update Update CLI/pgpm (installs pgpm by default)
20
- cache Manage cached templates (clean)
21
- upgrade-modules Upgrade installed pgpm modules to latest versions
22
-
23
- Development Tools:
10
+ GraphQL Server:
24
11
  server Start a GraphQL server
25
12
  explorer Launch GraphiQL explorer interface
26
- docker Manage PostgreSQL Docker containers (start/stop)
27
- export Export database migrations from existing databases
28
- env Display environment configuration
29
13
 
30
14
  Code Generation:
31
15
  codegen Generate TypeScript types and SDK from GraphQL schema
32
16
  get-graphql-schema Fetch or build GraphQL schema SDL
33
17
 
34
- Database Administration:
35
- kill Terminate database connections and optionally drop databases
36
- install Install pgpm modules
37
- tag Add tags to changes for versioning
38
- clear Clear database state
39
- remove Remove database changes
40
- analyze Analyze database structure
41
- rename Rename database changes
42
- admin-users Manage admin users
43
-
44
- Testing:
45
- test-packages Run integration tests on all workspace packages
46
-
47
- Migration Tools:
48
- migrate Migration management subcommands
49
- init Initialize migration tracking
50
- status Show migration status
51
- list List all changes
52
- deps Show change dependencies
53
-
54
18
  Global Options:
55
19
  -h, --help Display this help information
56
20
  -v, --version Display version information
57
21
  --cwd <directory> Working directory (default: current directory)
58
22
 
59
23
  Individual Command Help:
60
- constructive <command> --help Display detailed help for specific command
61
- constructive <command> -h Display detailed help for specific command
24
+ cnc <command> --help Display detailed help for specific command
25
+ cnc <command> -h Display detailed help for specific command
62
26
 
63
27
  Examples:
64
- cnc deploy --help Show deploy command options
65
- cnc server --port 8080 Start server on port 8080
66
- cnc init workspace Initialize new workspace
28
+ cnc server Start GraphQL server
29
+ cnc server --port 8080 Start server on custom port
30
+ cnc explorer Launch GraphiQL explorer
31
+ cnc codegen --schema schema.graphql Generate types from schema
32
+ cnc get-graphql-schema --out schema.graphql Export schema SDL
33
+
34
+ Database Operations:
35
+ For database migrations, packages, and deployment, use pgpm:
36
+ https://pgpm.io
67
37
  `;
package/utils/index.d.ts CHANGED
@@ -1,3 +1,3 @@
1
- export { extractFirst } from 'pgpm';
2
- export { cliExitWithError } from 'pgpm';
1
+ export { extractFirst } from './argv';
2
+ export { cliExitWithError } from './cli-error';
3
3
  export { usageText } from './display';
package/utils/index.js CHANGED
@@ -1,9 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.usageText = exports.cliExitWithError = exports.extractFirst = void 0;
4
- var pgpm_1 = require("pgpm");
5
- Object.defineProperty(exports, "extractFirst", { enumerable: true, get: function () { return pgpm_1.extractFirst; } });
6
- var pgpm_2 = require("pgpm");
7
- Object.defineProperty(exports, "cliExitWithError", { enumerable: true, get: function () { return pgpm_2.cliExitWithError; } });
4
+ var argv_1 = require("./argv");
5
+ Object.defineProperty(exports, "extractFirst", { enumerable: true, get: function () { return argv_1.extractFirst; } });
6
+ var cli_error_1 = require("./cli-error");
7
+ Object.defineProperty(exports, "cliExitWithError", { enumerable: true, get: function () { return cli_error_1.cliExitWithError; } });
8
8
  var display_1 = require("./display");
9
9
  Object.defineProperty(exports, "usageText", { enumerable: true, get: function () { return display_1.usageText; } });
@@ -0,0 +1,15 @@
1
+ export interface CheckForUpdatesOptions {
2
+ pkgName?: string;
3
+ pkgVersion?: string;
4
+ command?: string;
5
+ now?: number;
6
+ updateCommand?: string;
7
+ toolName?: string;
8
+ key?: string;
9
+ }
10
+ interface UpdateCheckConfig {
11
+ lastCheckedAt: number;
12
+ latestKnownVersion: string;
13
+ }
14
+ export declare function checkForUpdates(options?: CheckForUpdatesOptions): Promise<UpdateCheckConfig | null>;
15
+ export {};
@@ -0,0 +1,113 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.checkForUpdates = checkForUpdates;
7
+ const find_and_require_package_json_1 = require("find-and-require-package-json");
8
+ const logger_1 = require("@pgpmjs/logger");
9
+ const fs_1 = __importDefault(require("fs"));
10
+ const path_1 = __importDefault(require("path"));
11
+ const os_1 = __importDefault(require("os"));
12
+ const log = new logger_1.Logger('update-check');
13
+ const UPDATE_CHECK_TTL_MS = 7 * 24 * 60 * 60 * 1000; // 1 week
14
+ const shouldSkip = (command) => {
15
+ if (process.env.PGPM_SKIP_UPDATE_CHECK)
16
+ return true;
17
+ if (process.env.CI === 'true')
18
+ return true;
19
+ return false;
20
+ };
21
+ function getConfigPath(toolName, key) {
22
+ const configDir = path_1.default.join(os_1.default.homedir(), `.${toolName}`);
23
+ return path_1.default.join(configDir, `${key}.json`);
24
+ }
25
+ function readConfig(toolName, key) {
26
+ try {
27
+ const configPath = getConfigPath(toolName, key);
28
+ if (!fs_1.default.existsSync(configPath))
29
+ return null;
30
+ const content = fs_1.default.readFileSync(configPath, 'utf8');
31
+ return JSON.parse(content);
32
+ }
33
+ catch {
34
+ return null;
35
+ }
36
+ }
37
+ function writeConfig(toolName, key, config) {
38
+ try {
39
+ const configPath = getConfigPath(toolName, key);
40
+ const configDir = path_1.default.dirname(configPath);
41
+ if (!fs_1.default.existsSync(configDir)) {
42
+ fs_1.default.mkdirSync(configDir, { recursive: true });
43
+ }
44
+ fs_1.default.writeFileSync(configPath, JSON.stringify(config, null, 2));
45
+ }
46
+ catch {
47
+ // Ignore write errors
48
+ }
49
+ }
50
+ async function fetchLatestVersion(pkgName) {
51
+ try {
52
+ const response = await fetch(`https://registry.npmjs.org/${pkgName}/latest`);
53
+ if (!response.ok)
54
+ return null;
55
+ const data = await response.json();
56
+ return data.version || null;
57
+ }
58
+ catch {
59
+ return null;
60
+ }
61
+ }
62
+ function compareVersions(current, latest) {
63
+ const currentParts = current.replace(/^v/, '').split('.').map(Number);
64
+ const latestParts = latest.replace(/^v/, '').split('.').map(Number);
65
+ for (let i = 0; i < Math.max(currentParts.length, latestParts.length); i++) {
66
+ const c = currentParts[i] || 0;
67
+ const l = latestParts[i] || 0;
68
+ if (c < l)
69
+ return -1;
70
+ if (c > l)
71
+ return 1;
72
+ }
73
+ return 0;
74
+ }
75
+ async function checkForUpdates(options = {}) {
76
+ const { pkgName = '@constructive-io/cli', pkgVersion = (0, find_and_require_package_json_1.findAndRequirePackageJson)(__dirname).version, command, now = Date.now(), key = 'update-check', toolName = 'constructive' } = options;
77
+ if (shouldSkip(command)) {
78
+ return null;
79
+ }
80
+ try {
81
+ const existing = readConfig(toolName, key);
82
+ let latestKnownVersion = existing?.latestKnownVersion ?? pkgVersion;
83
+ const needsCheck = !existing?.lastCheckedAt || (now - existing.lastCheckedAt) > UPDATE_CHECK_TTL_MS;
84
+ if (needsCheck) {
85
+ const fetched = await fetchLatestVersion(pkgName);
86
+ if (fetched) {
87
+ latestKnownVersion = fetched;
88
+ }
89
+ writeConfig(toolName, key, {
90
+ lastCheckedAt: now,
91
+ latestKnownVersion
92
+ });
93
+ }
94
+ const comparison = compareVersions(pkgVersion, latestKnownVersion);
95
+ const isOutdated = comparison < 0;
96
+ if (isOutdated) {
97
+ const updateInstruction = options.updateCommand ?? `Run npm i -g ${pkgName}@latest to upgrade.`;
98
+ log.warn(`A new version of ${pkgName} is available (current ${pkgVersion}, latest ${latestKnownVersion}). ${updateInstruction}`);
99
+ writeConfig(toolName, key, {
100
+ lastCheckedAt: now,
101
+ latestKnownVersion
102
+ });
103
+ }
104
+ return {
105
+ lastCheckedAt: now,
106
+ latestKnownVersion
107
+ };
108
+ }
109
+ catch (error) {
110
+ log.debug('Update check skipped due to error:', error);
111
+ return null;
112
+ }
113
+ }