statelyai 0.3.7 → 0.4.0

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 CHANGED
@@ -4,6 +4,7 @@ CLI implementation for Stately.
4
4
 
5
5
  This package contains the `statelyai` command implementation.
6
6
 
7
+ <!-- happy-path CLI usage and statelyai.json shape derived from packages/cli/src/cli.ts#COMMANDS and packages/cli/src/projectConfig.ts -->
7
8
  ## Happy Path
8
9
 
9
10
  1. Get an API key from [Stately API Key settings](https://stately.ai/registry/user/my-settings?tab=API+Key).
@@ -25,18 +26,40 @@ statelyai init
25
26
  statelyai init --scan
26
27
  ```
27
28
 
29
+ That writes a `statelyai.json` like:
30
+
31
+ ```json
32
+ {
33
+ "$schema": "https://stately.ai/schemas/statelyai.json",
34
+ "version": "1.0.0",
35
+ "projectId": "project_123",
36
+ "studioUrl": "https://stately.ai",
37
+ "defaultXStateVersion": 5,
38
+ "include": ["src/**/*.ts"],
39
+ "exclude": ["**/*.test.*", "**/*.spec.*"]
40
+ }
41
+ ```
42
+
28
43
  5. Push local machines:
29
44
 
30
45
  ```bash
31
46
  statelyai push
32
47
  ```
33
48
 
49
+ Preview what `push` would do without updating Studio or local files:
50
+
51
+ ```bash
52
+ statelyai push --dry-run
53
+ ```
54
+
34
55
  6. Pull remote changes back into linked local files:
35
56
 
36
57
  ```bash
37
58
  statelyai pull
38
59
  ```
39
60
 
61
+ `pull` skips locally modified files unless you pass `--force`.
62
+
40
63
  Run it without installing it globally:
41
64
 
42
65
  ```bash
package/dist/bin.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { l as run } from "./cli-B9CRx5db.mjs";
2
+ import { u as run } from "./cli-DvtWVXpM.mjs";
3
3
 
4
4
  //#region src/bin.ts
5
5
  run();
@@ -945,6 +945,15 @@ const CODE_SOURCE_EXTENSIONS = new Set([
945
945
  ".cjs"
946
946
  ]);
947
947
  const execFileAsync$1 = promisify(execFile);
948
+ const ALWAYS_IGNORED_DIRECTORIES = new Set([
949
+ ".git",
950
+ "node_modules",
951
+ "dist",
952
+ "build",
953
+ "out",
954
+ "coverage",
955
+ ".next"
956
+ ]);
948
957
  function createStatelyProjectConfig(options) {
949
958
  const defaultXStateVersion = options.defaultXStateVersion ?? 5;
950
959
  return {
@@ -953,21 +962,20 @@ function createStatelyProjectConfig(options) {
953
962
  projectId: options.projectId,
954
963
  studioUrl: options.studioUrl,
955
964
  defaultXStateVersion,
956
- sources: []
957
- };
958
- }
959
- function normalizeSourceConfig(source) {
960
- return {
961
- include: [...source.include ?? []],
962
- exclude: source.exclude == null ? [...DEFAULT_SOURCE_EXCLUDES] : [...source.exclude],
963
- format: source.format ?? "xstate",
964
- ...source.xstateVersion == null ? {} : { xstateVersion: source.xstateVersion }
965
+ include: [],
966
+ exclude: [...DEFAULT_SOURCE_EXCLUDES]
965
967
  };
966
968
  }
967
969
  function normalizeProjectConfig(config) {
970
+ const firstSource = config.sources?.[0];
968
971
  return {
969
- ...config,
970
- sources: (config.sources ?? []).map((source) => normalizeSourceConfig(source))
972
+ $schema: config.$schema ?? STATELY_CONFIG_SCHEMA_URL,
973
+ version: config.version ?? STATELY_CONFIG_VERSION,
974
+ projectId: config.projectId ?? "",
975
+ studioUrl: config.studioUrl ?? "https://stately.ai",
976
+ defaultXStateVersion: Math.max(5, config.defaultXStateVersion ?? 5),
977
+ include: [...config.include ?? firstSource?.include ?? []],
978
+ exclude: config.exclude == null ? [...firstSource?.exclude ?? DEFAULT_SOURCE_EXCLUDES] : [...config.exclude]
971
979
  };
972
980
  }
973
981
  async function readStatelyProjectConfig(options = {}) {
@@ -984,7 +992,7 @@ async function walkFiles(rootDir, currentDir = rootDir) {
984
992
  const entries = await fsPromises.readdir(currentDir, { withFileTypes: true });
985
993
  const files = [];
986
994
  for (const entry of entries) {
987
- if (entry.name === ".git") continue;
995
+ if (ALWAYS_IGNORED_DIRECTORIES.has(entry.name)) continue;
988
996
  const absolutePath = path.join(currentDir, entry.name);
989
997
  if (entry.isDirectory()) {
990
998
  files.push(...await walkFiles(rootDir, absolutePath));
@@ -996,21 +1004,14 @@ async function walkFiles(rootDir, currentDir = rootDir) {
996
1004
  return files;
997
1005
  }
998
1006
  async function filterGitIgnoredPaths(rootDir, relativeFiles) {
1007
+ if (relativeFiles.length === 0) return relativeFiles;
999
1008
  try {
1000
- const { stdout } = await execFileAsync$1("git", [
1001
- "ls-files",
1002
- "--others",
1003
- "--ignored",
1004
- "--exclude-standard",
1005
- "--directory"
1006
- ], { cwd: rootDir });
1009
+ const { stdout } = await execFileAsync$1("git", ["check-ignore", ...relativeFiles], { cwd: rootDir });
1007
1010
  const ignoredEntries = stdout.split(/\r?\n/).map((entry) => entry.trim()).filter(Boolean);
1008
1011
  if (ignoredEntries.length === 0) return relativeFiles;
1012
+ const ignoredPaths = new Set(ignoredEntries);
1009
1013
  return relativeFiles.filter((relativePath) => {
1010
- return !ignoredEntries.some((ignoredEntry) => {
1011
- if (ignoredEntry.endsWith("/")) return relativePath.startsWith(ignoredEntry);
1012
- return relativePath === ignoredEntry;
1013
- });
1014
+ return !ignoredPaths.has(relativePath);
1014
1015
  });
1015
1016
  } catch {
1016
1017
  return relativeFiles;
@@ -1063,30 +1064,51 @@ async function discoverCodeSourceFiles(options = {}) {
1063
1064
  const rootDir = path.resolve(options.cwd ?? process.cwd());
1064
1065
  return (await filterGitIgnoredPaths(rootDir, await walkFiles(rootDir))).filter((relativePath) => isCodeSourceFile(relativePath)).filter((relativePath) => !matchesAny(DEFAULT_SOURCE_EXCLUDES, relativePath)).sort((left, right) => left.localeCompare(right));
1065
1066
  }
1066
- function createSuggestedSource(include) {
1067
+ function createSuggestedConfig(include) {
1067
1068
  return {
1068
1069
  include: [include],
1069
- exclude: [...DEFAULT_SOURCE_EXCLUDES],
1070
- format: "xstate",
1071
- xstateVersion: 5
1070
+ exclude: [...DEFAULT_SOURCE_EXCLUDES]
1072
1071
  };
1073
1072
  }
1074
- function suggestStatelySourceConfigs(relativePaths, defaultXStateVersion = 5) {
1073
+ function toExtensionToken(extname) {
1074
+ return extname.startsWith(".") ? extname.slice(1) : extname;
1075
+ }
1076
+ function formatExtensionPattern(extnames) {
1077
+ const unique = [...new Set(extnames.map(toExtensionToken))].sort();
1078
+ if (unique.length === 1) return `.${unique[0]}`;
1079
+ return `.{${unique.join(",")}}`;
1080
+ }
1081
+ function getSuggestionRoot(relativePath) {
1082
+ if (relativePath.startsWith("src/")) return "src/";
1083
+ const packageMatch = relativePath.match(/^packages\/([^/]+)\/src\//);
1084
+ if (packageMatch) return `packages/${packageMatch[1]}/src/`;
1085
+ const appMatch = relativePath.match(/^apps\/([^/]+)\/src\//);
1086
+ if (appMatch) return `apps/${appMatch[1]}/src/`;
1087
+ return null;
1088
+ }
1089
+ function suggestGroupedInclude(relativePaths, root) {
1090
+ const extPattern = formatExtensionPattern(relativePaths.map((relativePath) => path.posix.extname(relativePath)));
1091
+ if (relativePaths.map((relativePath) => path.posix.basename(relativePath, path.posix.extname(relativePath))).every((basename) => basename.toLowerCase().endsWith("machine"))) return `${root}**/*machine${extPattern}`;
1092
+ return `${root}**/*${extPattern}`;
1093
+ }
1094
+ function suggestStatelySourceConfigs(relativePaths) {
1075
1095
  const pending = new Set(relativePaths.map((relativePath) => relativePath.replace(/\\/g, "/")).filter(Boolean));
1076
1096
  const suggestions = [];
1077
1097
  const addSuggestion = (include, predicate) => {
1078
1098
  const matched = [...pending].filter(predicate);
1079
1099
  if (matched.length === 0) return;
1080
- suggestions.push({
1081
- ...createSuggestedSource(include),
1082
- xstateVersion: defaultXStateVersion
1083
- });
1100
+ suggestions.push(createSuggestedConfig(include));
1084
1101
  for (const matchedPath of matched) pending.delete(matchedPath);
1085
1102
  };
1086
- addSuggestion("**/*.machine.ts", (relativePath) => relativePath.endsWith(".machine.ts"));
1087
- addSuggestion("src/**/*.{ts,tsx,js,jsx,mts,cts,mjs,cjs}", (relativePath) => relativePath.startsWith("src/"));
1088
- addSuggestion("packages/*/src/**/*.{ts,tsx,js,jsx,mts,cts,mjs,cjs}", (relativePath) => /^packages\/[^/]+\/src\//.test(relativePath));
1089
- addSuggestion("apps/*/src/**/*.{ts,tsx,js,jsx,mts,cts,mjs,cjs}", (relativePath) => /^apps\/[^/]+\/src\//.test(relativePath));
1103
+ const groupedRoots = /* @__PURE__ */ new Map();
1104
+ for (const relativePath of pending) {
1105
+ const root = getSuggestionRoot(relativePath);
1106
+ if (!root) continue;
1107
+ const bucket = groupedRoots.get(root) ?? [];
1108
+ bucket.push(relativePath);
1109
+ groupedRoots.set(root, bucket);
1110
+ }
1111
+ for (const [root, groupedPaths] of [...groupedRoots.entries()].sort((left, right) => left[0].localeCompare(right[0]))) addSuggestion(suggestGroupedInclude(groupedPaths, root), (relativePath) => groupedPaths.includes(relativePath));
1090
1112
  const byDirectory = /* @__PURE__ */ new Map();
1091
1113
  for (const relativePath of pending) {
1092
1114
  const directory = path.posix.dirname(relativePath);
@@ -1112,7 +1134,13 @@ async function discoverStatelySourceFiles(options = {}) {
1112
1134
  } : await readStatelyProjectConfig(options);
1113
1135
  const relativeFiles = await filterGitIgnoredPaths(rootDir, await walkFiles(rootDir));
1114
1136
  const discovered = /* @__PURE__ */ new Map();
1115
- for (const source of config.sources) for (const relativePath of relativeFiles) {
1137
+ const source = {
1138
+ include: config.include,
1139
+ exclude: config.exclude ?? DEFAULT_SOURCE_EXCLUDES,
1140
+ format: "xstate",
1141
+ xstateVersion: config.defaultXStateVersion
1142
+ };
1143
+ for (const relativePath of relativeFiles) {
1116
1144
  if (!matchesAny(source.include, relativePath)) continue;
1117
1145
  if (matchesAny(source.exclude, relativePath)) continue;
1118
1146
  const filePath = path.join(rootDir, relativePath);
@@ -1414,13 +1442,28 @@ async function scanProjectSources(options) {
1414
1442
  const filePath = path.join(cwd, relativePath);
1415
1443
  if (looksLikeXStateMachineSource(await fsPromises.readFile(filePath, "utf8"))) machineRelativePaths.push(relativePath);
1416
1444
  }
1417
- return suggestStatelySourceConfigs(machineRelativePaths, Math.max(5, options.defaultXStateVersion ?? 5));
1445
+ return suggestStatelySourceConfigs(machineRelativePaths);
1418
1446
  }
1419
1447
  function looksLikeXStateMachineSource(source) {
1420
1448
  const hasXStateImport = /from\s+['"]xstate(?:\/[^'"]+)?['"]/.test(source) || /require\(\s*['"]xstate(?:\/[^'"]+)?['"]\s*\)/.test(source);
1421
1449
  const hasMachineFactory = /\bcreateMachine\s*\(/.test(source) || /\.createMachine\s*\(/.test(source);
1422
1450
  return hasXStateImport && hasMachineFactory;
1423
1451
  }
1452
+ async function classifyPushCandidates(files) {
1453
+ const machineFiles = [];
1454
+ const nonMachineFiles = [];
1455
+ for (const file of files) {
1456
+ if (looksLikeXStateMachineSource(await fsPromises.readFile(file.filePath, "utf8"))) {
1457
+ machineFiles.push(file);
1458
+ continue;
1459
+ }
1460
+ nonMachineFiles.push(file);
1461
+ }
1462
+ return {
1463
+ machineFiles,
1464
+ nonMachineFiles
1465
+ };
1466
+ }
1424
1467
  function supportsMachineDiscovery(file) {
1425
1468
  return file.source.format === "xstate" || file.source.format === "auto";
1426
1469
  }
@@ -1629,14 +1672,28 @@ var PushCommand = class PushCommand extends Command {
1629
1672
  help: Flags.help({ char: "h" }),
1630
1673
  "api-key": Flags.string({ description: "Stately API key used to create or update remote machines" }),
1631
1674
  "base-url": Flags.string({ description: "Base URL for Stately Studio or a self-hosted deployment" }),
1632
- config: Flags.string({ description: "Path to statelyai.json" })
1675
+ config: Flags.string({ description: "Path to statelyai.json" }),
1676
+ "dry-run": Flags.boolean({
1677
+ description: "Show which matched files contain machines and what push would do without changing remote or local state",
1678
+ default: false
1679
+ })
1633
1680
  };
1634
1681
  async run() {
1635
1682
  const { args, flags } = await this.parse(PushCommand);
1636
- const resolvedApiKey = await resolveApiKey(flags["api-key"]);
1637
- if (!resolvedApiKey.apiKey) this.error(getMissingApiKeyMessage());
1683
+ const resolvedApiKey = flags["dry-run"] ? { source: "missing" } : await resolveApiKey(flags["api-key"]);
1684
+ if (!flags["dry-run"] && !resolvedApiKey.apiKey) this.error(getMissingApiKeyMessage());
1638
1685
  this.log("Resolving configured project and source files...");
1639
- const { client, config, files } = await resolveConfiguredProject({
1686
+ const { client, config, files } = flags["dry-run"] ? await (async () => {
1687
+ const { config, rootDir } = await readStatelyProjectConfig({ configPath: flags.config });
1688
+ return {
1689
+ client: void 0,
1690
+ config,
1691
+ files: await discoverStatelySourceFiles({
1692
+ cwd: rootDir,
1693
+ config
1694
+ })
1695
+ };
1696
+ })() : await resolveConfiguredProject({
1640
1697
  apiKey: resolvedApiKey.apiKey,
1641
1698
  baseUrl: flags["base-url"],
1642
1699
  configPath: flags.config
@@ -1646,6 +1703,7 @@ var PushCommand = class PushCommand extends Command {
1646
1703
  relativePath: path.relative(process.cwd(), path.resolve(args.file)),
1647
1704
  source: {
1648
1705
  include: [args.file],
1706
+ exclude: [],
1649
1707
  format: "xstate",
1650
1708
  xstateVersion: config.defaultXStateVersion
1651
1709
  }
@@ -1654,11 +1712,29 @@ var PushCommand = class PushCommand extends Command {
1654
1712
  this.log("No matching local machine source files were discovered.");
1655
1713
  return;
1656
1714
  }
1657
- this.log(`Processing ${candidateFiles.length} ${pluralize(candidateFiles.length, "source file")}...`);
1715
+ const { machineFiles } = await classifyPushCandidates(candidateFiles);
1716
+ if (machineFiles.length === 0) {
1717
+ this.log(`Matched ${candidateFiles.length} ${pluralize(candidateFiles.length, "file")}, but no local machine sources were discovered.`);
1718
+ return;
1719
+ }
1720
+ this.log(`Discovered ${machineFiles.length} ${pluralize(machineFiles.length, "file with a machine")} from ${candidateFiles.length} matched ${pluralize(candidateFiles.length, "file")}.`);
1721
+ if (flags["dry-run"]) {
1722
+ const wouldLink = [];
1723
+ const wouldUpdate = [];
1724
+ for (const file of machineFiles) {
1725
+ const pragma = getStatelyPragma(await fsPromises.readFile(file.filePath, "utf8"), file.filePath);
1726
+ if (pragma?.id) wouldUpdate.push(`${file.relativePath}: ${pragma.id}`);
1727
+ else wouldLink.push(file.relativePath);
1728
+ }
1729
+ if (wouldLink.length > 0) this.log(`Would link:\n${wouldLink.join("\n")}`);
1730
+ if (wouldUpdate.length > 0) this.log(`Would update:\n${wouldUpdate.join("\n")}`);
1731
+ return;
1732
+ }
1733
+ this.log(`Processing ${machineFiles.length} ${pluralize(machineFiles.length, "source file")}...`);
1658
1734
  const linked = [];
1659
1735
  const refreshed = [];
1660
1736
  const skipped = [];
1661
- for (const file of candidateFiles) {
1737
+ for (const file of machineFiles) {
1662
1738
  this.log(`Pushing ${file.relativePath}...`);
1663
1739
  if (!supportsMachineDiscovery(file)) {
1664
1740
  skipped.push(`${file.relativePath}: unsupported format ${file.source.format}`);
@@ -1776,7 +1852,7 @@ var InitCommand = class InitCommand extends Command {
1776
1852
  defaultXStateVersion: result.config.defaultXStateVersion
1777
1853
  });
1778
1854
  if (suggestions.length === 0) {
1779
- this.log(`${initMessage}\nNo machine source globs were suggested. Edit statelyai.json before running statelyai push.`);
1855
+ this.log(`${initMessage}\nNo include globs were suggested from files with a machine. Edit statelyai.json before running statelyai push.`);
1780
1856
  return;
1781
1857
  }
1782
1858
  this.log(initMessage);
@@ -1784,14 +1860,15 @@ var InitCommand = class InitCommand extends Command {
1784
1860
  if (await promptYesNo("Save these source globs to statelyai.json?", true)) {
1785
1861
  const nextConfig = {
1786
1862
  ...result.config,
1787
- sources: suggestions
1863
+ include: suggestions.flatMap((suggestion) => suggestion.include),
1864
+ exclude: [...new Set(suggestions.flatMap((suggestion) => suggestion.exclude ?? []))]
1788
1865
  };
1789
1866
  await fsPromises.writeFile(result.configPath, `${JSON.stringify(nextConfig, null, 2)}\n`, "utf8");
1790
1867
  this.log("Saved scanned source globs to statelyai.json.");
1791
- } else this.log("Left statelyai.json with an empty sources array. Edit it before running statelyai push.");
1868
+ } else this.log("Left statelyai.json unchanged. Edit it before running statelyai push.");
1792
1869
  return;
1793
1870
  }
1794
- this.log(`${initMessage}\nNo source globs configured yet. Edit statelyai.json before running statelyai push, or rerun with --scan.`);
1871
+ this.log(`${initMessage}\nNo include globs configured yet. Edit statelyai.json before running statelyai push, or rerun with --scan.`);
1795
1872
  }
1796
1873
  };
1797
1874
  var LoginCommand = class LoginCommand extends Command {
@@ -1883,4 +1960,4 @@ function isDirectExecution() {
1883
1960
  if (isDirectExecution()) run$1();
1884
1961
 
1885
1962
  //#endregion
1886
- export { inferInitProjectName as a, resolveApiKey as c, createStatelyProjectConfig as d, getEnvApiKey as i, run$1 as l, discoverLinkedPullTargets as n, initProject as o, formatPlanSummary as r, isFileGitDirty as s, COMMANDS as t, scanProjectSources as u };
1963
+ export { getEnvApiKey as a, isFileGitDirty as c, scanProjectSources as d, createStatelyProjectConfig as f, formatPlanSummary as i, resolveApiKey as l, classifyPushCandidates as n, inferInitProjectName as o, discoverLinkedPullTargets as r, initProject as s, COMMANDS as t, run$1 as u };
package/dist/index.d.mts CHANGED
@@ -16,7 +16,8 @@ interface StatelyProjectConfig {
16
16
  projectId: string;
17
17
  studioUrl: string;
18
18
  defaultXStateVersion: number;
19
- sources: StatelySourceConfig[];
19
+ include: string[];
20
+ exclude?: string[];
20
21
  }
21
22
  interface DiscoveredSourceFile {
22
23
  filePath: string;
@@ -54,6 +55,10 @@ interface LinkedPullTarget {
54
55
  file: DiscoveredSourceFile;
55
56
  machineId: string;
56
57
  }
58
+ interface PushCandidateClassification {
59
+ machineFiles: DiscoveredSourceFile[];
60
+ nonMachineFiles: DiscoveredSourceFile[];
61
+ }
57
62
  type ApiKeyResolution = {
58
63
  apiKey: string;
59
64
  detail: string;
@@ -72,7 +77,8 @@ declare function inferInitProjectName(cwd: string, repo?: ConnectedRepo): string
72
77
  declare function isFileGitDirty(filePath: string): Promise<boolean>;
73
78
  declare function discoverLinkedPullTargets(files: DiscoveredSourceFile[]): Promise<LinkedPullTarget[]>;
74
79
  declare function initProject(options: InitProjectOptions): Promise<InitProjectResult>;
75
- declare function scanProjectSources(options: ScanProjectSourcesOptions): Promise<StatelySourceConfig[]>;
80
+ declare function scanProjectSources(options: ScanProjectSourcesOptions): Promise<Array<Pick<StatelyProjectConfig, 'include' | 'exclude'>>>;
81
+ declare function classifyPushCandidates(files: DiscoveredSourceFile[]): Promise<PushCandidateClassification>;
76
82
  declare function formatPlanSummary(plan: SyncPlan): string;
77
83
  declare abstract class BaseSyncCommand extends Command {
78
84
  static enableJsonFlag: boolean;
@@ -142,6 +148,7 @@ declare class PushCommand extends Command {
142
148
  'api-key': _oclif_core_interfaces0.OptionFlag<string | undefined, _oclif_core_interfaces0.CustomOptions>;
143
149
  'base-url': _oclif_core_interfaces0.OptionFlag<string | undefined, _oclif_core_interfaces0.CustomOptions>;
144
150
  config: _oclif_core_interfaces0.OptionFlag<string | undefined, _oclif_core_interfaces0.CustomOptions>;
151
+ 'dry-run': _oclif_core_interfaces0.BooleanFlag<boolean>;
145
152
  };
146
153
  run(): Promise<void>;
147
154
  }
@@ -220,4 +227,4 @@ declare const COMMANDS: {
220
227
  };
221
228
  declare function run(argv?: any, entryUrl?: string): Promise<void>;
222
229
  //#endregion
223
- export { ApiKeyResolution, COMMANDS, InitProjectOptions, InitProjectResult, LinkedPullTarget, ScanProjectSourcesOptions, createStatelyProjectConfig, discoverLinkedPullTargets, formatPlanSummary, getEnvApiKey, inferInitProjectName, initProject, isFileGitDirty, resolveApiKey, run, scanProjectSources };
230
+ export { ApiKeyResolution, COMMANDS, InitProjectOptions, InitProjectResult, LinkedPullTarget, PushCandidateClassification, ScanProjectSourcesOptions, classifyPushCandidates, createStatelyProjectConfig, discoverLinkedPullTargets, formatPlanSummary, getEnvApiKey, inferInitProjectName, initProject, isFileGitDirty, resolveApiKey, run, scanProjectSources };
package/dist/index.mjs CHANGED
@@ -1,3 +1,3 @@
1
- import { a as inferInitProjectName, c as resolveApiKey, d as createStatelyProjectConfig, i as getEnvApiKey, l as run, n as discoverLinkedPullTargets, o as initProject, r as formatPlanSummary, s as isFileGitDirty, t as COMMANDS, u as scanProjectSources } from "./cli-B9CRx5db.mjs";
1
+ import { a as getEnvApiKey, c as isFileGitDirty, d as scanProjectSources, f as createStatelyProjectConfig, i as formatPlanSummary, l as resolveApiKey, n as classifyPushCandidates, o as inferInitProjectName, r as discoverLinkedPullTargets, s as initProject, t as COMMANDS, u as run } from "./cli-DvtWVXpM.mjs";
2
2
 
3
- export { COMMANDS, createStatelyProjectConfig, discoverLinkedPullTargets, formatPlanSummary, getEnvApiKey, inferInitProjectName, initProject, isFileGitDirty, resolveApiKey, run, scanProjectSources };
3
+ export { COMMANDS, classifyPushCandidates, createStatelyProjectConfig, discoverLinkedPullTargets, formatPlanSummary, getEnvApiKey, inferInitProjectName, initProject, isFileGitDirty, resolveApiKey, run, scanProjectSources };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "statelyai",
3
- "version": "0.3.7",
3
+ "version": "0.4.0",
4
4
  "description": "Command-line tools for Stately",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -21,7 +21,7 @@
21
21
  },
22
22
  "dependencies": {
23
23
  "@oclif/core": "^4.10.3",
24
- "@statelyai/sdk": "0.8.1"
24
+ "@statelyai/sdk": "0.9.0"
25
25
  },
26
26
  "devDependencies": {
27
27
  "tsdown": "0.21.0-beta.2",