create-factory 0.1.6 → 0.1.7-alpha.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/CHANGELOG.md +9 -0
- package/dist/index.js +94 -83
- package/package.json +2 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
# create-factory
|
|
2
2
|
|
|
3
|
+
## 0.1.7-alpha.0
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Use the same PostHog analytics as create-mastra in the create-factory CLI, including the MASTRA_TELEMETRY_DISABLED opt-out and shared anonymous distinct id. ([#20073](https://github.com/mastra-ai/mastra/pull/20073))
|
|
8
|
+
|
|
9
|
+
- Updated dependencies [[`ed5d606`](https://github.com/mastra-ai/mastra/commit/ed5d606739c5e3fbdfa9f272df7809aa5ab43b1d)]:
|
|
10
|
+
- mastra@1.23.1-alpha.0
|
|
11
|
+
|
|
3
12
|
## 0.1.6
|
|
4
13
|
|
|
5
14
|
### Patch Changes
|
package/dist/index.js
CHANGED
|
@@ -1,85 +1,14 @@
|
|
|
1
1
|
#! /usr/bin/env node
|
|
2
|
-
import fs, {
|
|
2
|
+
import fs, { readFileSync } from "node:fs";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
5
|
import { Command } from "commander";
|
|
6
|
-
import {
|
|
7
|
-
import os from "node:os";
|
|
8
|
-
import { PostHog } from "posthog-node";
|
|
6
|
+
import { PosthogAnalytics, setAnalytics } from "mastra/dist/analytics/index.js";
|
|
9
7
|
import * as p from "@clack/prompts";
|
|
10
8
|
import { LoginCancelledError, MASTRA_PLATFORM_API_URL, authHeaders, extractApiErrorDetail, fetchOrgs, getToken, loadCredentials, platformFetch, resolveCurrentOrg } from "mastra/internal/auth";
|
|
11
9
|
import color from "picocolors";
|
|
12
10
|
import { x } from "tinyexec";
|
|
13
11
|
import fs$1 from "node:fs/promises";
|
|
14
|
-
//#region src/analytics.ts
|
|
15
|
-
/**
|
|
16
|
-
* Minimal PostHog analytics for create-factory, mirroring the
|
|
17
|
-
* create-mastra pattern (same project key, same opt-out env var, same
|
|
18
|
-
* ~/.mastra/analytics.json distinct-id store).
|
|
19
|
-
*/
|
|
20
|
-
const ANALYTICS_CONFIG_PATH = path.join(os.homedir(), ".mastra", "analytics.json");
|
|
21
|
-
const POSTHOG_API_KEY = "phc_SBLpZVAB6jmHOct9CABq3PF0Yn5FU3G2FgT4xUr2XrT";
|
|
22
|
-
const POSTHOG_HOST = "https://us.posthog.com";
|
|
23
|
-
function isTelemetryEnabled() {
|
|
24
|
-
const value = process.env.MASTRA_TELEMETRY_DISABLED;
|
|
25
|
-
return !(value && value !== "0" && value.toLowerCase() !== "false");
|
|
26
|
-
}
|
|
27
|
-
function getOrCreateDistinctId() {
|
|
28
|
-
try {
|
|
29
|
-
if (existsSync(ANALYTICS_CONFIG_PATH)) {
|
|
30
|
-
const { distinctId } = JSON.parse(readFileSync(ANALYTICS_CONFIG_PATH, "utf-8"));
|
|
31
|
-
if (distinctId) return distinctId;
|
|
32
|
-
}
|
|
33
|
-
} catch {}
|
|
34
|
-
const distinctId = randomUUID();
|
|
35
|
-
try {
|
|
36
|
-
mkdirSync(path.dirname(ANALYTICS_CONFIG_PATH), { recursive: true });
|
|
37
|
-
writeFileSync(ANALYTICS_CONFIG_PATH, JSON.stringify({
|
|
38
|
-
distinctId,
|
|
39
|
-
sessionId: randomUUID()
|
|
40
|
-
}, null, 2));
|
|
41
|
-
} catch {}
|
|
42
|
-
return distinctId;
|
|
43
|
-
}
|
|
44
|
-
var Analytics = class {
|
|
45
|
-
version;
|
|
46
|
-
client;
|
|
47
|
-
distinctId = "";
|
|
48
|
-
constructor(version) {
|
|
49
|
-
this.version = version;
|
|
50
|
-
if (!isTelemetryEnabled()) return;
|
|
51
|
-
try {
|
|
52
|
-
this.distinctId = getOrCreateDistinctId();
|
|
53
|
-
this.client = new PostHog(POSTHOG_API_KEY, {
|
|
54
|
-
host: POSTHOG_HOST,
|
|
55
|
-
flushAt: 1,
|
|
56
|
-
flushInterval: 100
|
|
57
|
-
});
|
|
58
|
-
} catch {
|
|
59
|
-
this.client = void 0;
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
trackEvent(event, properties = {}) {
|
|
63
|
-
try {
|
|
64
|
-
this.client?.capture({
|
|
65
|
-
distinctId: this.distinctId,
|
|
66
|
-
event,
|
|
67
|
-
properties: {
|
|
68
|
-
...properties,
|
|
69
|
-
cli: "create-factory",
|
|
70
|
-
version: this.version
|
|
71
|
-
}
|
|
72
|
-
});
|
|
73
|
-
} catch {}
|
|
74
|
-
}
|
|
75
|
-
async shutdown(timeoutMs = 1e3) {
|
|
76
|
-
if (!this.client) return;
|
|
77
|
-
try {
|
|
78
|
-
await Promise.race([this.client.shutdown(), new Promise((resolve) => setTimeout(resolve, timeoutMs))]);
|
|
79
|
-
} catch {}
|
|
80
|
-
}
|
|
81
|
-
};
|
|
82
|
-
//#endregion
|
|
83
12
|
//#region src/env.ts
|
|
84
13
|
/**
|
|
85
14
|
* Idempotently update a `.env` file.
|
|
@@ -653,19 +582,101 @@ function ensureEnvGitignored(projectPath) {
|
|
|
653
582
|
fs.writeFileSync(gitignorePath, `${existing}${prefix}\n# Added by create-factory to protect platform credentials\n.env\n`);
|
|
654
583
|
}
|
|
655
584
|
//#endregion
|
|
585
|
+
//#region src/utils/redact.ts
|
|
586
|
+
/**
|
|
587
|
+
* Sanitizes error messages before they are sent to analytics.
|
|
588
|
+
*
|
|
589
|
+
* Failure telemetry reports `error.message`, and several failure paths embed
|
|
590
|
+
* user-supplied input in their messages: a clone failure includes the full
|
|
591
|
+
* `git clone <url>` command (a custom template URL can identify a private repo
|
|
592
|
+
* and may carry embedded credentials), and `--region`/`--org` validation
|
|
593
|
+
* errors echo the raw flag value back. The user still sees the original
|
|
594
|
+
* message on stderr — only the analytics copy is redacted.
|
|
595
|
+
*/
|
|
596
|
+
const REDACTED = "[redacted]";
|
|
597
|
+
/** Strips `user:password@` credentials from any URL in the message. */
|
|
598
|
+
function stripUrlCredentials(message) {
|
|
599
|
+
return message.replace(/\/\/[^\s/@]+@/g, `//${REDACTED}@`);
|
|
600
|
+
}
|
|
601
|
+
/**
|
|
602
|
+
* A value can surface in messages in derived forms: without embedded
|
|
603
|
+
* credentials (git may omit them when echoing the URL) or with the
|
|
604
|
+
* `https://github.com/` prefix stripped (degit's repo shorthand).
|
|
605
|
+
*/
|
|
606
|
+
function variantsOf(value) {
|
|
607
|
+
const variants = /* @__PURE__ */ new Set([value, value.replace(/\/\/[^\s/@]+@/g, "//")]);
|
|
608
|
+
for (const variant of [...variants]) if (variant.startsWith("https://github.com/")) variants.add(variant.slice(19));
|
|
609
|
+
return [...variants];
|
|
610
|
+
}
|
|
611
|
+
/**
|
|
612
|
+
* Redacts every literal occurrence (and derived variant) of the provided
|
|
613
|
+
* user-supplied values, any URL credentials, and the org list echoed by
|
|
614
|
+
* `--org` mismatch errors.
|
|
615
|
+
*/
|
|
616
|
+
function redactErrorMessage(message, sensitiveValues = []) {
|
|
617
|
+
let redacted = message;
|
|
618
|
+
for (const value of sensitiveValues) {
|
|
619
|
+
if (!value) continue;
|
|
620
|
+
for (const variant of variantsOf(value)) redacted = redacted.split(variant).join(REDACTED);
|
|
621
|
+
}
|
|
622
|
+
redacted = stripUrlCredentials(redacted);
|
|
623
|
+
redacted = redacted.replace(/Available: .*$/s, `Available: ${REDACTED}.`);
|
|
624
|
+
return redacted;
|
|
625
|
+
}
|
|
626
|
+
/** Returns a copy of `error` safe to report to analytics. */
|
|
627
|
+
function redactError(error, sensitiveValues = []) {
|
|
628
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
629
|
+
return new Error(redactErrorMessage(message, sensitiveValues));
|
|
630
|
+
}
|
|
631
|
+
//#endregion
|
|
656
632
|
//#region src/index.ts
|
|
657
633
|
const pkg = JSON.parse(readFileSync(path.join(path.dirname(fileURLToPath(import.meta.url)), "..", "package.json"), "utf8"));
|
|
658
|
-
const analytics = new
|
|
634
|
+
const analytics = new PosthogAnalytics({
|
|
635
|
+
apiKey: "phc_SBLpZVAB6jmHOct9CABq3PF0Yn5FU3G2FgT4xUr2XrT",
|
|
636
|
+
host: "https://us.posthog.com",
|
|
637
|
+
version: pkg.version
|
|
638
|
+
});
|
|
639
|
+
setAnalytics(analytics);
|
|
659
640
|
const program = new Command();
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
641
|
+
const DEFAULT_TEMPLATE_REPO = "https://github.com/mastra-ai/softwarefactory-template";
|
|
642
|
+
program.name("create-factory").description("Create a new Mastra Factory project").argument("[project-name]", "Directory name of the project").option("--template <template-name>", "Create a project from a template (public GitHub URL)", DEFAULT_TEMPLATE_REPO).option("--no-platform", "Skip Mastra platform sign-in, project, and Neon provisioning").option("--org <org>", "Mastra organization id or name — skips the interactive org picker").option("--region <region>", "Platform project region (eu or us); prompts when omitted").version(pkg.version, "-v, --version").action(async (projectNameArg, args) => {
|
|
643
|
+
const region = args.region ? String(args.region) : void 0;
|
|
644
|
+
const validRegion = region === "eu" || region === "us" ? region : void 0;
|
|
645
|
+
const sensitiveValues = [
|
|
646
|
+
args.template === DEFAULT_TEMPLATE_REPO ? void 0 : args.template,
|
|
647
|
+
args.org ? String(args.org) : void 0,
|
|
648
|
+
validRegion ? void 0 : region,
|
|
649
|
+
projectNameArg
|
|
650
|
+
];
|
|
651
|
+
let rawError;
|
|
652
|
+
try {
|
|
653
|
+
await analytics.trackCommandExecution({
|
|
654
|
+
command: "create-factory",
|
|
655
|
+
args: {
|
|
656
|
+
default_template: args.template === DEFAULT_TEMPLATE_REPO,
|
|
657
|
+
no_platform: args.platform === false,
|
|
658
|
+
has_org: Boolean(args.org),
|
|
659
|
+
region: validRegion ?? (region ? "invalid" : void 0)
|
|
660
|
+
},
|
|
661
|
+
execution: async () => {
|
|
662
|
+
try {
|
|
663
|
+
await create({
|
|
664
|
+
projectName: projectNameArg,
|
|
665
|
+
template: args.template,
|
|
666
|
+
noPlatform: args.platform === false,
|
|
667
|
+
org: args.org ? String(args.org) : void 0,
|
|
668
|
+
region,
|
|
669
|
+
analytics
|
|
670
|
+
});
|
|
671
|
+
} catch (err) {
|
|
672
|
+
rawError = err;
|
|
673
|
+
throw redactError(err, sensitiveValues);
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
});
|
|
677
|
+
} catch (err) {
|
|
678
|
+
throw rawError ?? err;
|
|
679
|
+
}
|
|
669
680
|
});
|
|
670
681
|
try {
|
|
671
682
|
await program.parseAsync(process.argv);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-factory",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.7-alpha.0",
|
|
4
4
|
"description": "Create a Mastra Factory project: an agent-powered software delivery environment built on Mastra. Run `npm create factory` to scaffold and get started.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -36,9 +36,8 @@
|
|
|
36
36
|
"@clack/prompts": "^1.7.0",
|
|
37
37
|
"commander": "^14.0.3",
|
|
38
38
|
"picocolors": "^1.1.1",
|
|
39
|
-
"posthog-node": "^5.37.0",
|
|
40
39
|
"tinyexec": "^1.2.4",
|
|
41
|
-
"mastra": "1.23.0"
|
|
40
|
+
"mastra": "1.23.1-alpha.0"
|
|
42
41
|
},
|
|
43
42
|
"devDependencies": {
|
|
44
43
|
"@types/node": "22.20.1",
|