@factorialco/fcode-cli 1.1.1 → 1.2.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 +1 -1
- package/dist/core/executors/javascript-execution-task.js +8 -1
- package/dist/env.d.ts +43 -0
- package/dist/env.js +53 -0
- package/dist/hooks/init/update.js +6 -8
- package/dist/runtime/libs/python/fcode/context.py +19 -0
- package/oclif.manifest.json +1 -1
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -20,7 +20,7 @@ $ npm install -g @factorialco/fcode-cli
|
|
|
20
20
|
$ fcode COMMAND
|
|
21
21
|
running command...
|
|
22
22
|
$ fcode (--version)
|
|
23
|
-
@factorialco/fcode-cli/1.
|
|
23
|
+
@factorialco/fcode-cli/1.2.0 linux-x64 node-v22.22.3
|
|
24
24
|
$ fcode --help [COMMAND]
|
|
25
25
|
USAGE
|
|
26
26
|
$ fcode COMMAND
|
|
@@ -587,7 +587,14 @@ const main = typeof _hooksModule['${fn}'] === 'function'
|
|
|
587
587
|
console.log('[fcode] variables.delete removed ' + key + ' from variables.local.env (local run).');
|
|
588
588
|
}
|
|
589
589
|
};
|
|
590
|
-
})()
|
|
590
|
+
})(),
|
|
591
|
+
sendMail: async ({ to, subject, text, html } = {}) => {
|
|
592
|
+
// No manager locally: log the email contents instead of sending, so
|
|
593
|
+
// devs can see exactly what would be delivered when run in the cloud.
|
|
594
|
+
console.log('[fcode] sendMail (local run) — not sent, logging contents below:');
|
|
595
|
+
console.log(JSON.stringify({ to, subject, text, html }, null, 2));
|
|
596
|
+
return { messageId: 'local-run', accepted: [].concat(to || []), rejected: [] };
|
|
597
|
+
}
|
|
591
598
|
};
|
|
592
599
|
${Object.entries(this.getVariablesObject())
|
|
593
600
|
.map(([key, value]) => `process.env['${key}'] = process.env['${key}'] ?? ${JSON.stringify(value)}`)
|
package/dist/env.d.ts
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
/**
|
|
3
|
+
* Validated environment schema for the fcode CLI. This is the single source of truth
|
|
4
|
+
* for the environment variables the CLI reads — add new vars here.
|
|
5
|
+
*
|
|
6
|
+
* Unlike the long-running services (storage-api, ai), a CLI reads config lazily and
|
|
7
|
+
* different commands need different vars, so there is currently NO universally required
|
|
8
|
+
* variable: every entry is optional or carries a default that preserves prior behavior.
|
|
9
|
+
* The fail-fast (❌ + exit 1) path is kept for parity with the services and so that a
|
|
10
|
+
* genuinely-required var added later fails at process start listing every problem.
|
|
11
|
+
*/
|
|
12
|
+
export declare const envSchema: z.ZodObject<{
|
|
13
|
+
FCODE_CLOUD_URL: z.ZodDefault<z.ZodString>;
|
|
14
|
+
FCODE_AUTH_URL: z.ZodOptional<z.ZodString>;
|
|
15
|
+
FCODE_CLIENT_ID: z.ZodDefault<z.ZodString>;
|
|
16
|
+
FCODE_CONFIG_PATH: z.ZodOptional<z.ZodString>;
|
|
17
|
+
IGNORE_WORKSPACE_NOT_EMPTY: z.ZodOptional<z.ZodEnum<{
|
|
18
|
+
true: "true";
|
|
19
|
+
false: "false";
|
|
20
|
+
}>>;
|
|
21
|
+
FCODE_DISABLE_UPDATE_NOTIFIER: z.ZodOptional<z.ZodEnum<{
|
|
22
|
+
true: "true";
|
|
23
|
+
false: "false";
|
|
24
|
+
}>>;
|
|
25
|
+
SILENT_MODE: z.ZodOptional<z.ZodEnum<{
|
|
26
|
+
true: "true";
|
|
27
|
+
false: "false";
|
|
28
|
+
}>>;
|
|
29
|
+
CLI_UX_SKIP_TTY_CHECK: z.ZodOptional<z.ZodString>;
|
|
30
|
+
YC_COMMAND: z.ZodOptional<z.ZodString>;
|
|
31
|
+
}, z.core.$strip>;
|
|
32
|
+
export declare const env: {
|
|
33
|
+
FCODE_CLOUD_URL: string;
|
|
34
|
+
FCODE_CLIENT_ID: string;
|
|
35
|
+
FCODE_AUTH_URL?: string | undefined;
|
|
36
|
+
FCODE_CONFIG_PATH?: string | undefined;
|
|
37
|
+
IGNORE_WORKSPACE_NOT_EMPTY?: "true" | "false" | undefined;
|
|
38
|
+
FCODE_DISABLE_UPDATE_NOTIFIER?: "true" | "false" | undefined;
|
|
39
|
+
SILENT_MODE?: "true" | "false" | undefined;
|
|
40
|
+
CLI_UX_SKIP_TTY_CHECK?: string | undefined;
|
|
41
|
+
YC_COMMAND?: string | undefined;
|
|
42
|
+
};
|
|
43
|
+
export default env;
|
package/dist/env.js
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.env = exports.envSchema = void 0;
|
|
4
|
+
const zod_1 = require("zod");
|
|
5
|
+
/**
|
|
6
|
+
* Validated environment schema for the fcode CLI. This is the single source of truth
|
|
7
|
+
* for the environment variables the CLI reads — add new vars here.
|
|
8
|
+
*
|
|
9
|
+
* Unlike the long-running services (storage-api, ai), a CLI reads config lazily and
|
|
10
|
+
* different commands need different vars, so there is currently NO universally required
|
|
11
|
+
* variable: every entry is optional or carries a default that preserves prior behavior.
|
|
12
|
+
* The fail-fast (❌ + exit 1) path is kept for parity with the services and so that a
|
|
13
|
+
* genuinely-required var added later fails at process start listing every problem.
|
|
14
|
+
*/
|
|
15
|
+
exports.envSchema = zod_1.z.object({
|
|
16
|
+
// --- Cloud / auth endpoints ---
|
|
17
|
+
FCODE_CLOUD_URL: zod_1.z.string().min(1).default('https://code.factorial.dev/platform'),
|
|
18
|
+
FCODE_AUTH_URL: zod_1.z.string().min(1).optional(),
|
|
19
|
+
FCODE_CLIENT_ID: zod_1.z.string().min(1).default('cli'),
|
|
20
|
+
// --- Local config location (defaults to os.homedir() at the call site) ---
|
|
21
|
+
FCODE_CONFIG_PATH: zod_1.z.string().min(1).optional(),
|
|
22
|
+
// --- Behavior flags (compared as the strings 'true' / 'false' at the call sites) ---
|
|
23
|
+
IGNORE_WORKSPACE_NOT_EMPTY: zod_1.z.enum(['true', 'false']).optional(),
|
|
24
|
+
FCODE_DISABLE_UPDATE_NOTIFIER: zod_1.z.enum(['true', 'false']).optional(),
|
|
25
|
+
SILENT_MODE: zod_1.z.enum(['true', 'false']).optional(),
|
|
26
|
+
CLI_UX_SKIP_TTY_CHECK: zod_1.z.string().min(1).optional(),
|
|
27
|
+
// --- Debug tooling ---
|
|
28
|
+
YC_COMMAND: zod_1.z.string().min(1).optional(),
|
|
29
|
+
});
|
|
30
|
+
/** Treat empty strings (e.g. an unset shell/dotenv var rendered as "") as missing. */
|
|
31
|
+
const raw = Object.fromEntries(Object.entries(process.env).filter(([, value]) => value !== ''));
|
|
32
|
+
/**
|
|
33
|
+
* Skip the hard fail-fast under test runners and when explicitly opted out, so importing
|
|
34
|
+
* this module never kills a test worker. Real invocations always validate.
|
|
35
|
+
*/
|
|
36
|
+
const skipHardExit = Boolean(process.env.VITEST) || process.env.SKIP_ENV_VALIDATION === 'true';
|
|
37
|
+
const result = exports.envSchema.safeParse(raw);
|
|
38
|
+
let parsed;
|
|
39
|
+
if (result.success) {
|
|
40
|
+
parsed = result.data;
|
|
41
|
+
}
|
|
42
|
+
else if (skipHardExit) {
|
|
43
|
+
// No universally-required vars today, so parsing `raw` alone succeeds; this branch stays
|
|
44
|
+
// for parity with the services if a required var is ever added.
|
|
45
|
+
parsed = exports.envSchema.parse(raw);
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
const issues = result.error.issues.map((issue) => ` - ${issue.path.join('.') || '(root)'}: ${issue.message}`).join('\n');
|
|
49
|
+
process.stderr.write(`❌ Invalid environment variables:\n${issues}\n`);
|
|
50
|
+
process.exit(1);
|
|
51
|
+
}
|
|
52
|
+
exports.env = parsed;
|
|
53
|
+
exports.default = exports.env;
|
|
@@ -20,14 +20,12 @@ const updateNotifier = async function ({ config, id }) {
|
|
|
20
20
|
await globalConfig.set('versionCheckTime', now);
|
|
21
21
|
if (config.version !== lastestVersion) {
|
|
22
22
|
console.log(`
|
|
23
|
-
${color_1.default.cyan(`
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
| |
|
|
30
|
-
|_|`)}
|
|
23
|
+
${color_1.default.cyan(` ______ _ _ _ _____ _
|
|
24
|
+
| ____| | | (_) | |/ ____| | |
|
|
25
|
+
| |__ __ _ ___| |_ ___ _ __ _ __ _| | | ___ __| | ___
|
|
26
|
+
| __/ _\` |/ __| __/ _ \\| '__| |/ _\` | | | / _ \\ / _\` |/ _ \\
|
|
27
|
+
| | | (_| | (__| || (_) | | | | (_| | | |___| (_) | (_| | __/
|
|
28
|
+
|_| \\__,_|\\___|\\__\\___/|_| |_|\\__,_|_|\\_____\\___/ \\__,_|\\___|`)}
|
|
31
29
|
|
|
32
30
|
Update available ${color_1.default.red(config.version)} → ${color_1.default.greenBright(lastestVersion)}
|
|
33
31
|
Run ${color_1.default.bold('`npm i -g @factorialco/fcode-cli`')} to update
|
|
@@ -90,6 +90,25 @@ class FcodeGlobal:
|
|
|
90
90
|
self.variables = variables
|
|
91
91
|
self.processes = Processes()
|
|
92
92
|
|
|
93
|
+
def send_mail(self, to=None, subject=None, text=None, html=None):
|
|
94
|
+
# No manager locally: log the email contents instead of sending, so devs
|
|
95
|
+
# can see exactly what would be delivered when run in the cloud.
|
|
96
|
+
import json
|
|
97
|
+
import logging
|
|
98
|
+
|
|
99
|
+
logger = logging.getLogger("fcode_logger")
|
|
100
|
+
logger.info(
|
|
101
|
+
"[fcode] send_mail (local run) — not sent, logging contents below:"
|
|
102
|
+
)
|
|
103
|
+
logger.info(
|
|
104
|
+
json.dumps(
|
|
105
|
+
{"to": to, "subject": subject, "text": text, "html": html},
|
|
106
|
+
indent=2,
|
|
107
|
+
)
|
|
108
|
+
)
|
|
109
|
+
accepted = to if isinstance(to, list) else ([to] if to else [])
|
|
110
|
+
return {"messageId": "local-run", "accepted": accepted, "rejected": []}
|
|
111
|
+
|
|
93
112
|
def import_module(self, module_name, version=None):
|
|
94
113
|
module_path = module_name
|
|
95
114
|
if version:
|
package/oclif.manifest.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@factorialco/fcode-cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"packageManager": "pnpm@11.7.0",
|
|
5
5
|
"description": "Factorial Code Command Line Interface",
|
|
6
6
|
"homepage": "https://code.factorialhr.com/docs/cli/",
|
|
@@ -40,7 +40,8 @@
|
|
|
40
40
|
"open": "^8.4.2",
|
|
41
41
|
"openid-client": "^5.6.5",
|
|
42
42
|
"string-width": "^4.2.3",
|
|
43
|
-
"strip-comments": "^2.0.1"
|
|
43
|
+
"strip-comments": "^2.0.1",
|
|
44
|
+
"zod": "^4.4.3"
|
|
44
45
|
},
|
|
45
46
|
"peerDependencies": {
|
|
46
47
|
"graphql-request": "^7.4.0",
|