@openworkflow/cli 0.5.0 → 0.5.2
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/cli.js +18 -3
- package/dist/commands.d.ts +1 -0
- package/dist/commands.d.ts.map +1 -1
- package/dist/commands.js +41 -26
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +2 -0
- package/dist/telemetry.d.ts +16 -0
- package/dist/telemetry.d.ts.map +1 -0
- package/dist/telemetry.js +101 -0
- package/dist/templates.d.ts +6 -1
- package/dist/templates.d.ts.map +1 -1
- package/dist/templates.js +10 -2
- package/package.json +3 -2
package/dist/cli.js
CHANGED
|
@@ -2,14 +2,18 @@
|
|
|
2
2
|
/* v8 ignore file -- @preserve */
|
|
3
3
|
import { dashboard, doctor, getVersion, init, workerStart, } from "./commands.js";
|
|
4
4
|
import { withErrorHandling } from "./errors.js";
|
|
5
|
-
import {
|
|
5
|
+
import { initializeTelemetry, shutdownTelemetry, trackCommand, } from "./telemetry.js";
|
|
6
|
+
import { Command, CommanderError, Option } from "commander";
|
|
6
7
|
// openworkflow
|
|
7
8
|
const program = new Command();
|
|
9
|
+
initializeTelemetry(program);
|
|
8
10
|
program
|
|
9
11
|
.name("openworkflow")
|
|
10
12
|
.description("OpenWorkflow CLI - learn more at https://openworkflow.dev")
|
|
11
13
|
.usage("<command> [options]")
|
|
12
|
-
.
|
|
14
|
+
.exitOverride()
|
|
15
|
+
.version(getVersion())
|
|
16
|
+
.option("--no-telemetry", "disable telemetry");
|
|
13
17
|
// init
|
|
14
18
|
program
|
|
15
19
|
.command("init")
|
|
@@ -49,4 +53,15 @@ program
|
|
|
49
53
|
.option("--config <path>", "path to OpenWorkflow config file")
|
|
50
54
|
.option("--env-file <path>", "load environment variables from file")
|
|
51
55
|
.action(withErrorHandling(dashboard));
|
|
52
|
-
|
|
56
|
+
try {
|
|
57
|
+
await program.parseAsync(process.argv);
|
|
58
|
+
}
|
|
59
|
+
catch (error) {
|
|
60
|
+
if (!(error instanceof CommanderError))
|
|
61
|
+
throw error;
|
|
62
|
+
process.exitCode = error.exitCode;
|
|
63
|
+
trackCommand();
|
|
64
|
+
}
|
|
65
|
+
finally {
|
|
66
|
+
await shutdownTelemetry();
|
|
67
|
+
}
|
package/dist/commands.d.ts
CHANGED
package/dist/commands.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../commands.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,YAAY,EAIb,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../commands.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,YAAY,EAIb,MAAM,aAAa,CAAC;AAyCrB,KAAK,aAAa,GAAG,QAAQ,GAAG,UAAU,GAAG,MAAM,CAAC;AAEpD,UAAU,cAAc;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,UAAU,WAAY,SAAQ,cAAc;IAC1C,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,UAAU,gBAAiB,SAAQ,cAAc;IAC/C,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;GAGG;AACH,wBAAgB,UAAU,IAAI,MAAM,CAoBnC;AAED;;;;GAIG;AAEH,wBAAsB,IAAI,CAAC,OAAO,GAAE,WAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CA0JnE;AAkCD;;;GAGG;AACH,wBAAsB,MAAM,CAAC,OAAO,GAAE,cAAmB,GAAG,OAAO,CAAC,IAAI,CAAC,CA2DxE;AAED,MAAM,MAAM,kBAAkB,GAAG,YAAY,GAAG,cAAc,CAAC;AAE/D;;;GAGG;AACH,wBAAsB,WAAW,CAC/B,OAAO,GAAE,kBAAuB,GAC/B,OAAO,CAAC,IAAI,CAAC,CA8Ef;AAED;;;;;GAKG;AACH,wBAAgB,wBAAwB,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG;IACvD,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,YAAY,EAAE;QACZ,KAAK,EAAE,SAAS,CAAC;QACjB,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;KACzB,CAAC;CACH,CAYA;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAavE;AAED;;;;GAIG;AACH,wBAAsB,SAAS,CAAC,OAAO,GAAE,gBAAqB,GAAG,OAAO,CAAC,IAAI,CAAC,CA6D7E;AA4PD;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,MAAM,EAAE,EACd,OAAO,EAAE,MAAM,EACf,cAAc,GAAE,MAAM,EAAO,GAC5B,MAAM,EAAE,CA8CV;AAuXD,UAAU,oBAAoB;IAC5B,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC1C;AAoCD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAC/B,WAAW,EAAE,QAAQ,CAAC,oBAAoB,CAAC,GAAG,IAAI,GACjD,MAAM,CAER;AAED;;;;GAIG;AACH,wBAAgB,0BAA0B,CACxC,WAAW,EAAE,QAAQ,CAAC,oBAAoB,CAAC,GAAG,IAAI,GACjD,MAAM,CAER;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAC5B,WAAW,EAAE,QAAQ,CAAC,oBAAoB,CAAC,GAAG,IAAI,GACjD,MAAM,CAER;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAC/B,WAAW,EAAE,QAAQ,CAAC,oBAAoB,CAAC,GAAG,IAAI,GACjD,MAAM,CAER"}
|
package/dist/commands.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { findConfigFile, loadConfigFromPath, } from "./config.js";
|
|
2
2
|
import { CLIError, exit } from "./errors.js";
|
|
3
3
|
import { createModuleLoader } from "./module-loader.js";
|
|
4
|
-
import {
|
|
4
|
+
import { trackCommand } from "./telemetry.js";
|
|
5
|
+
import { getConfigTemplate, HELLO_WORLD_RUNNER, HELLO_WORLD_WORKFLOW, POSTGRES_CLIENT, POSTGRES_PROD_SQLITE_DEV_CLIENT, SQLITE_CLIENT, } from "./templates.js";
|
|
5
6
|
import * as p from "@clack/prompts";
|
|
6
7
|
import { consola } from "consola";
|
|
7
|
-
import { config as loadDotenv } from "dotenv";
|
|
8
|
+
import { config as loadDotenv, parse as parseDotenv } from "dotenv";
|
|
8
9
|
import { spawn } from "node:child_process";
|
|
9
10
|
import { existsSync, mkdirSync, readdirSync, readFileSync, unlinkSync, writeFileSync, } from "node:fs";
|
|
10
11
|
import path from "node:path";
|
|
@@ -40,6 +41,7 @@ export function getVersion() {
|
|
|
40
41
|
/**
|
|
41
42
|
* openworkflow init
|
|
42
43
|
* @param options - Command options
|
|
44
|
+
* @returns Resolves when setup finishes.
|
|
43
45
|
*/
|
|
44
46
|
// oxlint-disable-next-line complexity
|
|
45
47
|
export async function init(options = {}) {
|
|
@@ -61,7 +63,7 @@ export async function init(options = {}) {
|
|
|
61
63
|
initialValue: false,
|
|
62
64
|
});
|
|
63
65
|
if (!shouldOverride || p.isCancel(shouldOverride))
|
|
64
|
-
cancelSetup();
|
|
66
|
+
return cancelSetup();
|
|
65
67
|
configFileToDelete = configFile;
|
|
66
68
|
}
|
|
67
69
|
const backendChoice = options.backend ??
|
|
@@ -87,7 +89,8 @@ export async function init(options = {}) {
|
|
|
87
89
|
initialValue: "sqlite",
|
|
88
90
|
}));
|
|
89
91
|
if (typeof backendChoice === "symbol")
|
|
90
|
-
cancelSetup();
|
|
92
|
+
return cancelSetup();
|
|
93
|
+
trackCommand(backendChoice);
|
|
91
94
|
const spinner = p.spinner();
|
|
92
95
|
// detect package manager & install packages
|
|
93
96
|
spinner.start("Detecting package manager...");
|
|
@@ -98,7 +101,11 @@ export async function init(options = {}) {
|
|
|
98
101
|
if (!packageJson) {
|
|
99
102
|
throw new CLIError("No package.json found.", "Please create a package.json file first by running `npm init` or `npm init -y`.");
|
|
100
103
|
}
|
|
101
|
-
|
|
104
|
+
const configArg = options.config
|
|
105
|
+
? ` --config '${options.config.replaceAll("'", String.raw `'\''`)}'`
|
|
106
|
+
: "";
|
|
107
|
+
const workerCommand = `npx @openworkflow/cli worker start${configArg}`;
|
|
108
|
+
validateInitManifest(packageJson, workerCommand);
|
|
102
109
|
const configFileName = options.config ?? getConfigFileName(packageJson);
|
|
103
110
|
const clientFileName = getClientFileName(packageJson);
|
|
104
111
|
const exampleWorkflowFileName = getExampleWorkflowFileName(packageJson);
|
|
@@ -114,7 +121,7 @@ export async function init(options = {}) {
|
|
|
114
121
|
initialValue: true,
|
|
115
122
|
}));
|
|
116
123
|
if (p.isCancel(shouldSetup))
|
|
117
|
-
cancelSetup();
|
|
124
|
+
return cancelSetup();
|
|
118
125
|
if (!shouldSetup) {
|
|
119
126
|
p.outro("Setup skipped.");
|
|
120
127
|
return;
|
|
@@ -151,16 +158,16 @@ export async function init(options = {}) {
|
|
|
151
158
|
if (backendChoice === "postgres" || backendChoice === "both") {
|
|
152
159
|
updateEnvForPostgres();
|
|
153
160
|
}
|
|
154
|
-
addWorkerScriptToPackageJson();
|
|
161
|
+
addWorkerScriptToPackageJson(workerCommand);
|
|
155
162
|
// write config file last, so canceling earlier doesn't leave a config file
|
|
156
163
|
// which would prevent re-running init
|
|
157
164
|
createConfigFile(configFileName);
|
|
158
165
|
// wrap up
|
|
159
|
-
p.note(`➡️ Start a worker:\n$
|
|
166
|
+
p.note(`➡️ Start a worker:\n$ ${workerCommand}\n\n➡️ Run the example workflow:\n$ ${runCommand}\n\n➡️ View the dashboard:\n$ npx @openworkflow/cli dashboard${configArg}`, "Next steps");
|
|
160
167
|
p.outro("✅ Setup complete!");
|
|
161
168
|
}
|
|
162
169
|
// Validate the manifest fields that init reads or updates.
|
|
163
|
-
function validateInitManifest(manifest) {
|
|
170
|
+
function validateInitManifest(manifest, workerCommand) {
|
|
164
171
|
if (!manifest || typeof manifest !== "object" || Array.isArray(manifest)) {
|
|
165
172
|
throw new CLIError("Invalid package.json: expected an object.");
|
|
166
173
|
}
|
|
@@ -177,7 +184,9 @@ function validateInitManifest(manifest) {
|
|
|
177
184
|
}
|
|
178
185
|
const { scripts } = manifest;
|
|
179
186
|
const worker = scripts?.["worker"];
|
|
180
|
-
if (worker !== undefined &&
|
|
187
|
+
if (worker !== undefined &&
|
|
188
|
+
worker !== "npx @openworkflow/cli worker start" &&
|
|
189
|
+
worker !== workerCommand) {
|
|
181
190
|
throw new CLIError("Setup would overwrite package.json scripts.worker.");
|
|
182
191
|
}
|
|
183
192
|
}
|
|
@@ -380,11 +389,11 @@ export async function dashboard(options = {}) {
|
|
|
380
389
|
// -----------------------------------------------------------------------------
|
|
381
390
|
/**
|
|
382
391
|
* Show a canceled-setup message and exit the process with status 0.
|
|
392
|
+
* @returns Never resolves because the process exits.
|
|
383
393
|
*/
|
|
384
394
|
function cancelSetup() {
|
|
385
395
|
p.cancel("Setup canceled.");
|
|
386
|
-
|
|
387
|
-
process.exit(0);
|
|
396
|
+
return exit(0);
|
|
388
397
|
}
|
|
389
398
|
/**
|
|
390
399
|
* Exercise backend initialization, connectivity, and workflow table access.
|
|
@@ -707,9 +716,15 @@ function createConfigFile(configFileName) {
|
|
|
707
716
|
const spinner = p.spinner();
|
|
708
717
|
spinner.start("Writing config...");
|
|
709
718
|
const configDestPath = path.resolve(process.cwd(), configFileName);
|
|
719
|
+
const relativeClientPath = path
|
|
720
|
+
.relative(path.dirname(configDestPath), path.join(process.cwd(), "openworkflow/client.js"))
|
|
721
|
+
.replaceAll(path.sep, "/");
|
|
722
|
+
const clientImport = relativeClientPath.startsWith("../")
|
|
723
|
+
? relativeClientPath
|
|
724
|
+
: `./${relativeClientPath}`;
|
|
710
725
|
// mkdir if the user specified a config file, and they want it in a dir
|
|
711
726
|
mkdirSync(path.dirname(configDestPath), { recursive: true });
|
|
712
|
-
writeFileSync(configDestPath,
|
|
727
|
+
writeFileSync(configDestPath, getConfigTemplate(clientImport), "utf8");
|
|
713
728
|
spinner.stop(`Config written to ${configDestPath}`);
|
|
714
729
|
}
|
|
715
730
|
/**
|
|
@@ -777,8 +792,9 @@ function updateGitignoreForSqlite() {
|
|
|
777
792
|
}
|
|
778
793
|
/**
|
|
779
794
|
* Add worker script to package.json.
|
|
795
|
+
* @param workerCommand - Worker command including any custom config path.
|
|
780
796
|
*/
|
|
781
|
-
function addWorkerScriptToPackageJson() {
|
|
797
|
+
function addWorkerScriptToPackageJson(workerCommand) {
|
|
782
798
|
const packageJsonPath = path.join(process.cwd(), "package.json");
|
|
783
799
|
if (!existsSync(packageJsonPath)) {
|
|
784
800
|
return;
|
|
@@ -788,7 +804,7 @@ function addWorkerScriptToPackageJson() {
|
|
|
788
804
|
try {
|
|
789
805
|
const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf8"));
|
|
790
806
|
packageJson.scripts ??= {};
|
|
791
|
-
packageJson.scripts["worker"] =
|
|
807
|
+
packageJson.scripts["worker"] = workerCommand;
|
|
792
808
|
writeFileSync(packageJsonPath, `${JSON.stringify(packageJson, null, 2)}\n`, "utf8");
|
|
793
809
|
spinner.stop('Added "worker" script to package.json');
|
|
794
810
|
}
|
|
@@ -798,17 +814,17 @@ function addWorkerScriptToPackageJson() {
|
|
|
798
814
|
}
|
|
799
815
|
}
|
|
800
816
|
/**
|
|
801
|
-
* Append a line
|
|
802
|
-
* doesn't exist.
|
|
817
|
+
* Append a line if the file does not already contain the desired entry.
|
|
818
|
+
* Creates the file if it doesn't exist.
|
|
803
819
|
* @param filePath - Path to the file
|
|
804
820
|
* @param line - Line to append (without a trailing newline)
|
|
805
|
-
* @param matchesExisting - Predicate that
|
|
806
|
-
*
|
|
821
|
+
* @param matchesExisting - Predicate that checks whether the file contents
|
|
822
|
+
* already contain the desired entry
|
|
807
823
|
* @returns Whether the line was appended
|
|
808
824
|
*/
|
|
809
825
|
function appendLineIfMissing(filePath, line, matchesExisting) {
|
|
810
826
|
const content = existsSync(filePath) ? readFileSync(filePath, "utf8") : "";
|
|
811
|
-
if (
|
|
827
|
+
if (matchesExisting(content)) {
|
|
812
828
|
return false;
|
|
813
829
|
}
|
|
814
830
|
const separator = content === "" || content.endsWith("\n") ? "" : "\n";
|
|
@@ -823,7 +839,7 @@ function appendLineIfMissing(filePath, line, matchesExisting) {
|
|
|
823
839
|
* @returns Whether the entry was appended
|
|
824
840
|
*/
|
|
825
841
|
function ensureGitignoreEntry(gitignorePath, entry) {
|
|
826
|
-
return appendLineIfMissing(gitignorePath, entry, (line) => line.trim() === entry);
|
|
842
|
+
return appendLineIfMissing(gitignorePath, entry, (content) => content.split("\n").some((line) => line.trim() === entry));
|
|
827
843
|
}
|
|
828
844
|
/**
|
|
829
845
|
* Add OPENWORKFLOW_POSTGRES_URL to .env file.
|
|
@@ -861,7 +877,9 @@ function findConfigWithEnv(options) {
|
|
|
861
877
|
async function loadConfigWithEnv(options) {
|
|
862
878
|
const configPath = findConfigWithEnv(options);
|
|
863
879
|
try {
|
|
864
|
-
|
|
880
|
+
const loaded = await loadConfigFromPath(configPath ?? "openworkflow.config.ts");
|
|
881
|
+
trackCommand(loaded.config.backend);
|
|
882
|
+
return loaded;
|
|
865
883
|
}
|
|
866
884
|
catch (error) {
|
|
867
885
|
const message = error instanceof Error ? error.message : String(error);
|
|
@@ -946,10 +964,7 @@ function hasDependency(packageJson, name) {
|
|
|
946
964
|
* @returns Whether the entry was appended
|
|
947
965
|
*/
|
|
948
966
|
function ensureEnvEntry(envPath, key, value) {
|
|
949
|
-
return appendLineIfMissing(envPath, `${key}=${value}`, (
|
|
950
|
-
const trimmed = line.trim();
|
|
951
|
-
return trimmed.startsWith(`${key}=`) || trimmed.startsWith(`${key} =`);
|
|
952
|
-
});
|
|
967
|
+
return appendLineIfMissing(envPath, `${key}=${value}`, (content) => Object.hasOwn(parseDotenv(content), key));
|
|
953
968
|
}
|
|
954
969
|
/**
|
|
955
970
|
* Validate a numeric option is a positive integer.
|
package/dist/errors.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../errors.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../errors.ts"],"names":[],"mappings":"AAIA;;GAEG;AACH,qBAAa,QAAS,SAAQ,KAAK;IACjC,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;gBAExB,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM;CAK7C;AAED;;;GAGG;AACH,wBAAsB,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,CAYvD;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,SAAS,OAAO,EAAE,EACnD,EAAE,EAAE,CAAC,GAAG,IAAI,EAAE,CAAC,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,GACvC,CAAC,GAAG,IAAI,EAAE,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAiB/B"}
|
package/dist/errors.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
/* v8 ignore file -- @preserve */
|
|
2
|
+
import { shutdownTelemetry } from "./telemetry.js";
|
|
2
3
|
import { consola } from "consola";
|
|
3
4
|
/**
|
|
4
5
|
* User-facing CLI error.
|
|
@@ -16,6 +17,7 @@ export class CLIError extends Error {
|
|
|
16
17
|
* @param code - Process exit code
|
|
17
18
|
*/
|
|
18
19
|
export async function exit(code) {
|
|
20
|
+
await shutdownTelemetry();
|
|
19
21
|
await Promise.all([process.stdout, process.stderr].map((stream) => new Promise((resolve) => {
|
|
20
22
|
stream.end(resolve);
|
|
21
23
|
})));
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { Command } from "commander";
|
|
2
|
+
import type { Backend } from "openworkflow/internal";
|
|
3
|
+
/**
|
|
4
|
+
* Set up telemetry before the CLI prints output.
|
|
5
|
+
* @param program - Root CLI command
|
|
6
|
+
*/
|
|
7
|
+
export declare function initializeTelemetry(program: Command): void;
|
|
8
|
+
/**
|
|
9
|
+
* Track after loading config or choosing an init backend.
|
|
10
|
+
* Help, version, and argument errors are tracked without a backend.
|
|
11
|
+
* @param backend - Configured backend or init selection
|
|
12
|
+
*/
|
|
13
|
+
export declare function trackCommand(backend?: Backend | "sqlite" | "postgres" | "both"): void;
|
|
14
|
+
/** Send queued events before the CLI exits. */
|
|
15
|
+
export declare function shutdownTelemetry(): Promise<void>;
|
|
16
|
+
//# sourceMappingURL=telemetry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"telemetry.d.ts","sourceRoot":"","sources":["../telemetry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAKzC,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAoBrD;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAsC1D;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAC1B,OAAO,CAAC,EAAE,OAAO,GAAG,QAAQ,GAAG,UAAU,GAAG,MAAM,GACjD,IAAI,CAoCN;AAED,+CAA+C;AAC/C,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC,CAMvD"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { homedir } from "node:os";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import { PostHog } from "posthog-node";
|
|
6
|
+
let telemetry;
|
|
7
|
+
const backendTypes = new Map([
|
|
8
|
+
["BackendSqlite", "sqlite"],
|
|
9
|
+
["BackendPostgres", "postgres"],
|
|
10
|
+
["sqlite", "sqlite"],
|
|
11
|
+
["postgres", "postgres"],
|
|
12
|
+
["both", "both"],
|
|
13
|
+
]);
|
|
14
|
+
/**
|
|
15
|
+
* Set up telemetry before the CLI prints output.
|
|
16
|
+
* @param program - Root CLI command
|
|
17
|
+
*/
|
|
18
|
+
export function initializeTelemetry(program) {
|
|
19
|
+
telemetry = undefined;
|
|
20
|
+
if (process.env["DO_NOT_TRACK"] ||
|
|
21
|
+
process.env["OPENWORKFLOW_TELEMETRY_DISABLED"] ||
|
|
22
|
+
process.env["CI"] ||
|
|
23
|
+
process.argv.includes("--no-telemetry"))
|
|
24
|
+
return;
|
|
25
|
+
try {
|
|
26
|
+
const directory = path.join(homedir(), ".openworkflow");
|
|
27
|
+
const file = path.join(directory, "telemetry-id");
|
|
28
|
+
mkdirSync(directory, { recursive: true });
|
|
29
|
+
if (!existsSync(file)) {
|
|
30
|
+
writeFileSync(file, randomUUID(), { flag: "wx", mode: 0o600 });
|
|
31
|
+
console.error("OpenWorkflow collects CLI usage via PostHog. Set DO_NOT_TRACK=1 to opt out.\n" +
|
|
32
|
+
"https://openworkflow.dev/docs/cli#telemetry\n");
|
|
33
|
+
}
|
|
34
|
+
const distinctId = readFileSync(file, "utf8").trim();
|
|
35
|
+
if (!distinctId)
|
|
36
|
+
return;
|
|
37
|
+
const state = {
|
|
38
|
+
program,
|
|
39
|
+
distinctId,
|
|
40
|
+
client: new PostHog("phc_C1Cm1NAKHDFA3eKLVqcYzR5wUk8WhSbMMXltk5Qj1Ye"),
|
|
41
|
+
};
|
|
42
|
+
program.on("beforeAllHelp", ({ command }) => {
|
|
43
|
+
state.helpCommand = command;
|
|
44
|
+
});
|
|
45
|
+
program.on("option:version", () => {
|
|
46
|
+
state.version = true;
|
|
47
|
+
});
|
|
48
|
+
telemetry = state;
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
// ignore, telemetry is optional
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Track after loading config or choosing an init backend.
|
|
56
|
+
* Help, version, and argument errors are tracked without a backend.
|
|
57
|
+
* @param backend - Configured backend or init selection
|
|
58
|
+
*/
|
|
59
|
+
export function trackCommand(backend) {
|
|
60
|
+
const state = telemetry;
|
|
61
|
+
if (!state)
|
|
62
|
+
return;
|
|
63
|
+
try {
|
|
64
|
+
let command = state.helpCommand ?? state.program;
|
|
65
|
+
let child;
|
|
66
|
+
while ((child = command.commands.find((candidate) => candidate.name() === command.args[0]))) {
|
|
67
|
+
command = child;
|
|
68
|
+
}
|
|
69
|
+
const backendName = typeof backend === "string" ? backend : backend?.constructor.name;
|
|
70
|
+
const commandName = command.parent?.parent
|
|
71
|
+
? `${command.parent.name()} ${command.name()}`
|
|
72
|
+
: command.name();
|
|
73
|
+
state.client.capture({
|
|
74
|
+
distinctId: state.distinctId,
|
|
75
|
+
event: "cli_command_invoked",
|
|
76
|
+
properties: {
|
|
77
|
+
command: state.version ? "version" : commandName,
|
|
78
|
+
backend: backendName
|
|
79
|
+
? (backendTypes.get(backendName) ?? "custom")
|
|
80
|
+
: undefined,
|
|
81
|
+
help: state.helpCommand ? true : undefined,
|
|
82
|
+
cli_version: state.program.version(),
|
|
83
|
+
os: process.platform,
|
|
84
|
+
arch: process.arch,
|
|
85
|
+
node_version: process.versions.node,
|
|
86
|
+
},
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
// ignore, telemetry is optional
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
/** Send queued events before the CLI exits. */
|
|
94
|
+
export async function shutdownTelemetry() {
|
|
95
|
+
try {
|
|
96
|
+
await telemetry?.client.shutdown();
|
|
97
|
+
}
|
|
98
|
+
catch {
|
|
99
|
+
// ignore, telemetry is optional
|
|
100
|
+
}
|
|
101
|
+
}
|
package/dist/templates.d.ts
CHANGED
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
export declare const SQLITE_CLIENT = "import { BackendSqlite } from \"openworkflow/sqlite\";\nimport { OpenWorkflow } from \"openworkflow\";\n\nexport const backend = BackendSqlite.connect(\"openworkflow/backend.db\");\nexport const ow = new OpenWorkflow({ backend });\n";
|
|
2
2
|
export declare const POSTGRES_CLIENT = "import { BackendPostgres } from \"openworkflow/postgres\";\nimport { OpenWorkflow } from \"openworkflow\";\n\nexport const backend = await BackendPostgres.connect(\n process.env[\"OPENWORKFLOW_POSTGRES_URL\"],\n);\nexport const ow = new OpenWorkflow({ backend });\n";
|
|
3
3
|
export declare const POSTGRES_PROD_SQLITE_DEV_CLIENT = "import { BackendPostgres } from \"openworkflow/postgres\";\nimport { BackendSqlite } from \"openworkflow/sqlite\";\nimport { OpenWorkflow } from \"openworkflow\";\n\nexport const backend =\n process.env[\"NODE_ENV\"] === \"production\"\n ? await BackendPostgres.connect(process.env[\"OPENWORKFLOW_POSTGRES_URL\"])\n : BackendSqlite.connect(\"openworkflow/backend.db\");\nexport const ow = new OpenWorkflow({ backend });\n";
|
|
4
|
-
|
|
4
|
+
/**
|
|
5
|
+
* Render config paths relative to the config file's directory.
|
|
6
|
+
* @param clientImport - Relative import path to the scaffolded client.
|
|
7
|
+
* @returns The config template string.
|
|
8
|
+
*/
|
|
9
|
+
export declare function getConfigTemplate(clientImport: string): string;
|
|
5
10
|
export declare const HELLO_WORLD_WORKFLOW = "import { defineWorkflow } from \"openworkflow\";\n\n/**\n * Example workflow that greets the world.\n *\n * This workflow is auto-discovered by the CLI worker.\n * To trigger it, use ow.runWorkflow() from your app:\n * ```ts\n * import { ow } from \"./openworkflow/client.js\";\n * import { helloWorld } from \"./openworkflow/hello-world.js\";\n * const handle = await ow.runWorkflow(helloWorld.spec, {});\n * const result = await handle.result();\n * ```\n */\nexport const helloWorld = defineWorkflow(\n { name: \"hello-world\" },\n async ({ step }) => {\n const greeting = await step.run({ name: \"greet\" }, () => {\n return \"Hello, World!\";\n });\n\n await step.sleep(\"wait-a-bit\", \"1s\");\n\n return { greeting };\n },\n);\n";
|
|
6
11
|
export declare const HELLO_WORLD_RUNNER = "import { backend, ow } from \"./client.js\";\nimport { helloWorld } from \"./hello-world.js\";\n\n// Run this file:\n// JS: `node openworkflow/hello-world.run.js`\n// TS: `npx tsx openworkflow/hello-world.run.ts`\n//\n// This file is a temporary dev helper generated by\n// `npx @openworkflow/cli init` so you can quickly run the example workflow.\n//\n// Copy the code anywhere in your app (e.g., an API route or a script) and\n// modify it to run your workflows.\n//\n// You can delete this file once you're done with it.\n\nconsole.log(\"Running hello-world workflow...\");\nconst handle = await ow.runWorkflow(helloWorld.spec, {});\n\nconsole.log(\"Waiting for result...\");\nconst result = await handle.result(); // for very short workflows only\n\nconsole.log(`Workflow result: ${JSON.stringify(result, null, 2)}`);\n\n// Stop backend. Only needed if this is a standalone script that you want to\n// exit after running the workflow.\nawait backend.stop();\n";
|
|
7
12
|
//# sourceMappingURL=templates.d.ts.map
|
package/dist/templates.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"templates.d.ts","sourceRoot":"","sources":["../templates.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"templates.d.ts","sourceRoot":"","sources":["../templates.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,aAAa,6OAKzB,CAAC;AAEF,eAAO,MAAM,eAAe,+QAO3B,CAAC;AAEF,eAAO,MAAM,+BAA+B,ibAS3C,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAU9D;AAED,eAAO,MAAM,oBAAoB,wvBA0BhC,CAAC;AAEF,eAAO,MAAM,kBAAkB,w8BA0B9B,CAAC"}
|
package/dist/templates.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import path from "node:path";
|
|
1
2
|
export const SQLITE_CLIENT = `import { BackendSqlite } from "openworkflow/sqlite";
|
|
2
3
|
import { OpenWorkflow } from "openworkflow";
|
|
3
4
|
|
|
@@ -22,15 +23,22 @@ export const backend =
|
|
|
22
23
|
: BackendSqlite.connect("openworkflow/backend.db");
|
|
23
24
|
export const ow = new OpenWorkflow({ backend });
|
|
24
25
|
`;
|
|
25
|
-
|
|
26
|
+
/**
|
|
27
|
+
* Render config paths relative to the config file's directory.
|
|
28
|
+
* @param clientImport - Relative import path to the scaffolded client.
|
|
29
|
+
* @returns The config template string.
|
|
30
|
+
*/
|
|
31
|
+
export function getConfigTemplate(clientImport) {
|
|
32
|
+
return `import { backend } from ${JSON.stringify(clientImport)};
|
|
26
33
|
import { defineConfig } from "@openworkflow/cli";
|
|
27
34
|
|
|
28
35
|
export default defineConfig({
|
|
29
36
|
backend,
|
|
30
|
-
dirs:
|
|
37
|
+
dirs: ${JSON.stringify(path.posix.dirname(clientImport))},
|
|
31
38
|
ignorePatterns: ["**/*.run.*"],
|
|
32
39
|
});
|
|
33
40
|
`;
|
|
41
|
+
}
|
|
34
42
|
export const HELLO_WORLD_WORKFLOW = `import { defineWorkflow } from "openworkflow";
|
|
35
43
|
|
|
36
44
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openworkflow/cli",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": {
|
|
@@ -32,7 +32,8 @@
|
|
|
32
32
|
"consola": "^3.4.2",
|
|
33
33
|
"dotenv": "^17.4.2",
|
|
34
34
|
"jiti": "^2.7.0",
|
|
35
|
-
"nypm": "^0.6.10"
|
|
35
|
+
"nypm": "^0.6.10",
|
|
36
|
+
"posthog-node": "~5.21.2"
|
|
36
37
|
},
|
|
37
38
|
"devDependencies": {
|
|
38
39
|
"openworkflow": "*",
|