adfinem 0.1.0 → 0.1.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/src/cli.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import { Command } from "commander";
3
- import { writeFile } from "node:fs/promises";
3
+ import { access, cp, mkdir, writeFile } from "node:fs/promises";
4
4
  import { basename, dirname, join, resolve } from "node:path";
5
5
  import { fileURLToPath } from "node:url";
6
6
  import { ZodError } from "zod";
@@ -22,13 +22,60 @@ import { loadFlow, readFlowSource, writeFlow } from "./flows/parser.js";
22
22
  import { validateFlow } from "./flows/validator.js";
23
23
  import { concatFlows, type FlowNodePrefixMode } from "./flows/concat.js";
24
24
 
25
- const rootDir = resolve(dirname(fileURLToPath(import.meta.url)), "..");
25
+ const packageRoot = resolve(dirname(fileURLToPath(import.meta.url)), "..");
26
+ const rootDir = resolve(process.env.ADFINEM_PROJECT_ROOT ?? process.cwd());
26
27
  const program = new Command();
27
28
 
28
29
  program
29
30
  .name("adfinem")
30
31
  .description("Adfinem deterministic API, database, and Unix scenario runner")
31
- .version("0.1.0");
32
+ .version("0.1.1");
33
+
34
+ program
35
+ .command("init")
36
+ .argument("[directory]", "Project directory to create or update", ".")
37
+ .description("Create a starter Adfinem project with catalogs, config, scenarios, flows, docs, and templates")
38
+ .option("--force", "Overwrite starter files that already exist")
39
+ .action(async (directory: string, options: { force?: boolean }) => {
40
+ await handleErrors(async () => {
41
+ const targetRoot = resolve(process.cwd(), directory);
42
+ await mkdir(targetRoot, { recursive: true });
43
+ const entries = ["catalogs", "config", "flows", "scenarios", "templates", "docs", ".env.example"];
44
+ const copied: string[] = [];
45
+ const skipped: string[] = [];
46
+ for (const entry of entries) {
47
+ const source = join(packageRoot, entry);
48
+ const target = join(targetRoot, entry);
49
+ if (!options.force && await pathExists(target)) {
50
+ skipped.push(entry);
51
+ continue;
52
+ }
53
+ await cp(source, target, { recursive: true, force: Boolean(options.force) });
54
+ copied.push(entry);
55
+ }
56
+ console.log(`Adfinem project ready: ${targetRoot}`);
57
+ if (copied.length > 0) console.log(`Created: ${copied.join(", ")}`);
58
+ if (skipped.length > 0) console.log(`Skipped existing: ${skipped.join(", ")} (use --force to overwrite)`);
59
+ console.log("Next:");
60
+ console.log(` cd ${targetRoot}`);
61
+ console.log(" adfinem validate scenarios/smoke/account-processing-smoke.yaml");
62
+ console.log(" adfinem app");
63
+ });
64
+ });
65
+
66
+ program
67
+ .command("app")
68
+ .description("Start the Adfinem web workbench for the current project")
69
+ .option("--project <dir>", "Project root containing catalogs, config, scenarios, and flows", ".")
70
+ .option("--port <port>", "Port to bind; defaults to 4177 with fallback ports", parseInteger)
71
+ .action(async (options: { project: string; port?: number }) => {
72
+ await handleErrors(async () => {
73
+ process.env.ADFINEM_PROJECT_ROOT = resolve(process.cwd(), options.project);
74
+ process.env.ADFINEM_WEB_DIST = join(packageRoot, "web-dist");
75
+ if (options.port !== undefined) process.env.ADFINEM_RUNNER_PORT = String(options.port);
76
+ await import("./app/server.js");
77
+ });
78
+ });
32
79
 
33
80
  program
34
81
  .command("validate")
@@ -392,6 +439,10 @@ function parseInteger(value: string): number {
392
439
  return parsed;
393
440
  }
394
441
 
442
+ async function pathExists(path: string): Promise<boolean> {
443
+ return access(path).then(() => true).catch(() => false);
444
+ }
445
+
395
446
  function collectOption(value: string, previous: string[]): string[] {
396
447
  return [...previous, value];
397
448
  }