@ulpi/cli 0.1.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/LICENSE +21 -0
- package/README.md +200 -0
- package/dist/auth-PN7TMQHV-2W4ICG64.js +15 -0
- package/dist/chunk-247GVVKK.js +2259 -0
- package/dist/chunk-2CLNOKPA.js +793 -0
- package/dist/chunk-2HEE5OKX.js +79 -0
- package/dist/chunk-2MZER6ND.js +415 -0
- package/dist/chunk-3SBPZRB5.js +772 -0
- package/dist/chunk-4VNS5WPM.js +42 -0
- package/dist/chunk-6JCMYYBT.js +1546 -0
- package/dist/chunk-6OCEY7JY.js +422 -0
- package/dist/chunk-74WVVWJ4.js +375 -0
- package/dist/chunk-7AL4DOEJ.js +131 -0
- package/dist/chunk-7LXY5UVC.js +330 -0
- package/dist/chunk-DBMUNBNB.js +3048 -0
- package/dist/chunk-JWUUVXIV.js +13694 -0
- package/dist/chunk-KIKPIH6N.js +4048 -0
- package/dist/chunk-KLEASXUR.js +70 -0
- package/dist/chunk-MIAQVCFW.js +39 -0
- package/dist/chunk-NNUWU6CV.js +1610 -0
- package/dist/chunk-PKD4ASEM.js +115 -0
- package/dist/chunk-Q4HIY43N.js +4230 -0
- package/dist/chunk-QJ5GSMEC.js +146 -0
- package/dist/chunk-SIAQVRKG.js +2163 -0
- package/dist/chunk-SPOI23SB.js +197 -0
- package/dist/chunk-YM2HV4IA.js +505 -0
- package/dist/codemap-RRJIDBQ5.js +636 -0
- package/dist/config-EGAXXCGL.js +127 -0
- package/dist/dist-6G7JC2RA.js +90 -0
- package/dist/dist-7LHZ65GC.js +418 -0
- package/dist/dist-LZKZFPVX.js +140 -0
- package/dist/dist-R5F4MX3I.js +107 -0
- package/dist/dist-R5ZJ4LX5.js +56 -0
- package/dist/dist-RJGCUS3L.js +87 -0
- package/dist/dist-RKOGLK7R.js +151 -0
- package/dist/dist-W7K4WPAF.js +597 -0
- package/dist/export-import-4A5MWLIA.js +53 -0
- package/dist/history-ATTUKOHO.js +934 -0
- package/dist/index.js +2120 -0
- package/dist/init-AY5C2ZAS.js +393 -0
- package/dist/launchd-LF2QMSKZ.js +148 -0
- package/dist/log-TVTUXAYD.js +75 -0
- package/dist/mcp-installer-NQCGKQ23.js +124 -0
- package/dist/memory-J3G24QHS.js +406 -0
- package/dist/ollama-3XCUZMZT-FYKHW4TZ.js +7 -0
- package/dist/openai-E7G2YAHU-UYY4ZWON.js +8 -0
- package/dist/projects-ATHDD3D6.js +271 -0
- package/dist/review-ADUPV3PN.js +152 -0
- package/dist/rules-E427DKYJ.js +134 -0
- package/dist/server-MOYPE4SM-N7SE2AN7.js +18 -0
- package/dist/server-X5P6WH2M-7K2RY34N.js +11 -0
- package/dist/skills/ulpi-generate-guardian/SKILL.md +511 -0
- package/dist/skills/ulpi-generate-guardian/references/framework-rules.md +692 -0
- package/dist/skills/ulpi-generate-guardian/references/language-rules.md +596 -0
- package/dist/skills-CX73O3IV.js +76 -0
- package/dist/status-4DFHDJMN.js +66 -0
- package/dist/templates/biome.yml +24 -0
- package/dist/templates/conventional-commits.yml +18 -0
- package/dist/templates/django.yml +30 -0
- package/dist/templates/docker.yml +30 -0
- package/dist/templates/eslint.yml +13 -0
- package/dist/templates/express.yml +20 -0
- package/dist/templates/fastapi.yml +23 -0
- package/dist/templates/git-flow.yml +26 -0
- package/dist/templates/github-flow.yml +27 -0
- package/dist/templates/go.yml +33 -0
- package/dist/templates/jest.yml +24 -0
- package/dist/templates/laravel.yml +30 -0
- package/dist/templates/monorepo.yml +26 -0
- package/dist/templates/nestjs.yml +21 -0
- package/dist/templates/nextjs.yml +31 -0
- package/dist/templates/nodejs.yml +33 -0
- package/dist/templates/npm.yml +15 -0
- package/dist/templates/php.yml +25 -0
- package/dist/templates/pnpm.yml +15 -0
- package/dist/templates/prettier.yml +23 -0
- package/dist/templates/prisma.yml +21 -0
- package/dist/templates/python.yml +33 -0
- package/dist/templates/quality-of-life.yml +111 -0
- package/dist/templates/ruby.yml +25 -0
- package/dist/templates/rust.yml +34 -0
- package/dist/templates/typescript.yml +14 -0
- package/dist/templates/vitest.yml +24 -0
- package/dist/templates/yarn.yml +15 -0
- package/dist/templates-U7T6MARD.js +156 -0
- package/dist/ui-L7UAWXDY.js +167 -0
- package/dist/ui.html +698 -0
- package/dist/ulpi-RMMCUAGP-JCJ273T6.js +161 -0
- package/dist/uninstall-6SW35IK4.js +25 -0
- package/dist/update-M2B4RLGH.js +61 -0
- package/dist/version-checker-ANCS3IHR.js +10 -0
- package/package.json +92 -0
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
id: quality-of-life
|
|
2
|
+
name: Quality of Life
|
|
3
|
+
category: universal
|
|
4
|
+
|
|
5
|
+
# ============================================================================
|
|
6
|
+
# QUALITY OF LIFE TEMPLATE
|
|
7
|
+
# ============================================================================
|
|
8
|
+
# This template provides core safety rules without blocking legitimate work.
|
|
9
|
+
#
|
|
10
|
+
# Three-Tier Philosophy:
|
|
11
|
+
# 1. UNIVERSAL SAFETY - Block truly dangerous operations (narrow patterns)
|
|
12
|
+
# 2. WORKFLOW GUIDANCE - Guide best practices (context-aware, not blocking)
|
|
13
|
+
# 3. PRODUCTIVITY - Auto-approve safe operations (broad patterns)
|
|
14
|
+
#
|
|
15
|
+
# Built-In Protection:
|
|
16
|
+
# The evaluator automatically blocks dangerous commands with proper regex:
|
|
17
|
+
# - rm -rf / (root filesystem deletion)
|
|
18
|
+
# - sudo rm (privileged deletion)
|
|
19
|
+
# - chmod 777 (insecure permissions)
|
|
20
|
+
# - git push --force (without --force-with-lease)
|
|
21
|
+
# - git push to main/master
|
|
22
|
+
# - Database destruction (prisma reset, artisan wipe, rails drop, SQL DROP)
|
|
23
|
+
#
|
|
24
|
+
# You don't need custom rules for these unless you want stricter policies.
|
|
25
|
+
# ============================================================================
|
|
26
|
+
|
|
27
|
+
rules:
|
|
28
|
+
preconditions:
|
|
29
|
+
read-before-write:
|
|
30
|
+
enabled: true
|
|
31
|
+
trigger: PreToolUse
|
|
32
|
+
matcher: "Write|Edit|MultiEdit"
|
|
33
|
+
requires_read: true
|
|
34
|
+
message: "Read {file_path} before editing it."
|
|
35
|
+
locked: true
|
|
36
|
+
priority: 10
|
|
37
|
+
read-before-edit:
|
|
38
|
+
enabled: true
|
|
39
|
+
trigger: PreToolUse
|
|
40
|
+
matcher: "Edit|MultiEdit"
|
|
41
|
+
requires_read: true
|
|
42
|
+
message: "Read {file_path} first."
|
|
43
|
+
locked: true
|
|
44
|
+
priority: 10
|
|
45
|
+
no-empty-overwrites:
|
|
46
|
+
enabled: true
|
|
47
|
+
trigger: PreToolUse
|
|
48
|
+
matcher: "Write"
|
|
49
|
+
message: "You're overwriting with empty content. Provide actual content."
|
|
50
|
+
locked: true
|
|
51
|
+
priority: 10
|
|
52
|
+
branch-before-commit:
|
|
53
|
+
enabled: true
|
|
54
|
+
trigger: PreToolUse
|
|
55
|
+
matcher: "Bash"
|
|
56
|
+
command_pattern: "git commit"
|
|
57
|
+
requires: [branch_created]
|
|
58
|
+
message: "Create a feature branch first: git checkout -b feature/your-feature-name"
|
|
59
|
+
priority: 20
|
|
60
|
+
|
|
61
|
+
permissions:
|
|
62
|
+
auto-approve-reads:
|
|
63
|
+
enabled: true
|
|
64
|
+
trigger: PermissionRequest
|
|
65
|
+
matcher: "Read|LS|Glob|Grep"
|
|
66
|
+
decision: allow
|
|
67
|
+
priority: 100
|
|
68
|
+
|
|
69
|
+
block-env-files:
|
|
70
|
+
enabled: true
|
|
71
|
+
trigger: PreToolUse
|
|
72
|
+
matcher: "Write|Edit"
|
|
73
|
+
file_pattern: ".env*"
|
|
74
|
+
decision: deny
|
|
75
|
+
message: "Cannot edit .env files directly. Use .env.example as template."
|
|
76
|
+
priority: 50
|
|
77
|
+
|
|
78
|
+
# ============================================================================
|
|
79
|
+
# OPTIONAL RULES (Disabled by Default)
|
|
80
|
+
# ============================================================================
|
|
81
|
+
# The evaluator has built-in protection that blocks:
|
|
82
|
+
# - rm -rf / (root filesystem deletion)
|
|
83
|
+
# - sudo rm (privileged deletion)
|
|
84
|
+
# - chmod 777 (insecure permissions)
|
|
85
|
+
# - git push --force (without --force-with-lease)
|
|
86
|
+
# - git push to main/master
|
|
87
|
+
# - Database destruction (prisma reset, artisan wipe, etc.)
|
|
88
|
+
#
|
|
89
|
+
# Enable these rules only if you need CUSTOM patterns beyond the built-in protection.
|
|
90
|
+
|
|
91
|
+
custom-dangerous-commands:
|
|
92
|
+
enabled: false
|
|
93
|
+
trigger: PreToolUse
|
|
94
|
+
matcher: "Bash"
|
|
95
|
+
command_pattern: "your-custom-pattern-here"
|
|
96
|
+
decision: deny
|
|
97
|
+
message: "Custom dangerous command blocked."
|
|
98
|
+
# TIP: command_pattern uses PREFIX matching, not regex
|
|
99
|
+
# EXAMPLE: "docker rm -f" blocks "docker rm -f container-name"
|
|
100
|
+
# WARNING: Setting this rule disables built-in protection - be careful!
|
|
101
|
+
|
|
102
|
+
custom-auto-approvals:
|
|
103
|
+
enabled: false
|
|
104
|
+
trigger: PermissionRequest
|
|
105
|
+
matcher: "Bash"
|
|
106
|
+
command_pattern: "npm test"
|
|
107
|
+
decision: allow
|
|
108
|
+
message: "Auto-approved test command."
|
|
109
|
+
# TIP: Customize command_pattern for your project tools
|
|
110
|
+
# EXAMPLES: "pnpm", "vitest", "pytest", "cargo test"
|
|
111
|
+
# NOTE: Stack-specific templates provide better auto-approvals
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
id: ruby
|
|
2
|
+
name: Ruby
|
|
3
|
+
category: runtime
|
|
4
|
+
variables:
|
|
5
|
+
test_command: "bundle exec rspec"
|
|
6
|
+
lint_command: "bundle exec rubocop"
|
|
7
|
+
package_manager: bundle
|
|
8
|
+
|
|
9
|
+
rules:
|
|
10
|
+
preconditions:
|
|
11
|
+
test-before-commit:
|
|
12
|
+
enabled: true
|
|
13
|
+
trigger: PreToolUse
|
|
14
|
+
matcher: "Bash"
|
|
15
|
+
command_pattern: "git commit"
|
|
16
|
+
requires: [tests_run]
|
|
17
|
+
message: "Run {test_command} before committing."
|
|
18
|
+
postconditions:
|
|
19
|
+
bundle-install:
|
|
20
|
+
enabled: true
|
|
21
|
+
trigger: PostToolUse
|
|
22
|
+
matcher: "Write|Edit"
|
|
23
|
+
file_pattern: "Gemfile"
|
|
24
|
+
run: "bundle install"
|
|
25
|
+
timeout: 60000
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
id: rust
|
|
2
|
+
name: Rust
|
|
3
|
+
category: runtime
|
|
4
|
+
variables:
|
|
5
|
+
test_command: "cargo test"
|
|
6
|
+
lint_command: "cargo clippy"
|
|
7
|
+
build_command: "cargo build"
|
|
8
|
+
|
|
9
|
+
rules:
|
|
10
|
+
preconditions:
|
|
11
|
+
test-before-commit:
|
|
12
|
+
enabled: true
|
|
13
|
+
trigger: PreToolUse
|
|
14
|
+
matcher: "Bash"
|
|
15
|
+
command_pattern: "git commit"
|
|
16
|
+
requires: [tests_run]
|
|
17
|
+
message: "Run {test_command} before committing."
|
|
18
|
+
postconditions:
|
|
19
|
+
cargo-check-after-edit:
|
|
20
|
+
enabled: true
|
|
21
|
+
trigger: PostToolUse
|
|
22
|
+
matcher: "Write|Edit|MultiEdit"
|
|
23
|
+
file_pattern: "*.rs"
|
|
24
|
+
run: "cargo check"
|
|
25
|
+
timeout: 60000
|
|
26
|
+
block_on_failure: false
|
|
27
|
+
permissions:
|
|
28
|
+
auto-approve-cargo:
|
|
29
|
+
enabled: true
|
|
30
|
+
trigger: PermissionRequest
|
|
31
|
+
matcher: "Bash"
|
|
32
|
+
command_pattern: "cargo"
|
|
33
|
+
decision: allow
|
|
34
|
+
message: "Auto-approved cargo command."
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
id: typescript
|
|
2
|
+
name: TypeScript
|
|
3
|
+
category: language
|
|
4
|
+
|
|
5
|
+
rules:
|
|
6
|
+
postconditions:
|
|
7
|
+
typecheck-after-edit:
|
|
8
|
+
enabled: true
|
|
9
|
+
trigger: PostToolUse
|
|
10
|
+
matcher: "Write|Edit|MultiEdit"
|
|
11
|
+
file_pattern: "*.{ts,tsx}"
|
|
12
|
+
run: "npx tsc --noEmit"
|
|
13
|
+
timeout: 30000
|
|
14
|
+
block_on_failure: false
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
id: vitest
|
|
2
|
+
name: Vitest
|
|
3
|
+
category: test-runner
|
|
4
|
+
variables:
|
|
5
|
+
test_command: "npx vitest run"
|
|
6
|
+
|
|
7
|
+
rules:
|
|
8
|
+
permissions:
|
|
9
|
+
auto-approve-vitest:
|
|
10
|
+
enabled: true
|
|
11
|
+
trigger: PermissionRequest
|
|
12
|
+
matcher: "Bash"
|
|
13
|
+
command_pattern: "vitest"
|
|
14
|
+
decision: allow
|
|
15
|
+
message: "Auto-approved vitest command."
|
|
16
|
+
postconditions:
|
|
17
|
+
run-tests-after-edit:
|
|
18
|
+
enabled: true
|
|
19
|
+
trigger: PostToolUse
|
|
20
|
+
matcher: "Write|Edit|MultiEdit"
|
|
21
|
+
file_pattern: "*.{test,spec}.{ts,tsx,js,jsx}"
|
|
22
|
+
run: "npx vitest run {file_path}"
|
|
23
|
+
timeout: 30000
|
|
24
|
+
block_on_failure: false
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
id: yarn
|
|
2
|
+
name: Yarn
|
|
3
|
+
category: package-manager
|
|
4
|
+
variables:
|
|
5
|
+
package_manager: yarn
|
|
6
|
+
|
|
7
|
+
rules:
|
|
8
|
+
permissions:
|
|
9
|
+
auto-approve-yarn:
|
|
10
|
+
enabled: true
|
|
11
|
+
trigger: PermissionRequest
|
|
12
|
+
matcher: "Bash"
|
|
13
|
+
command_pattern: "yarn"
|
|
14
|
+
decision: allow
|
|
15
|
+
message: "Auto-approved yarn command."
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import {
|
|
2
|
+
deleteUserTemplate,
|
|
3
|
+
exportUserTemplate,
|
|
4
|
+
importUserTemplate,
|
|
5
|
+
listUserTemplates,
|
|
6
|
+
loadBundledTemplates,
|
|
7
|
+
saveUserTemplate
|
|
8
|
+
} from "./chunk-6OCEY7JY.js";
|
|
9
|
+
import {
|
|
10
|
+
loadRulesSync
|
|
11
|
+
} from "./chunk-SIAQVRKG.js";
|
|
12
|
+
import "./chunk-KIKPIH6N.js";
|
|
13
|
+
import "./chunk-7LXY5UVC.js";
|
|
14
|
+
import "./chunk-4VNS5WPM.js";
|
|
15
|
+
|
|
16
|
+
// src/commands/templates.ts
|
|
17
|
+
import * as fs from "fs";
|
|
18
|
+
import * as path from "path";
|
|
19
|
+
import chalk from "chalk";
|
|
20
|
+
async function runTemplates(args, _projectDir) {
|
|
21
|
+
const subcommand = args[0];
|
|
22
|
+
switch (subcommand) {
|
|
23
|
+
case "list":
|
|
24
|
+
return listTemplates();
|
|
25
|
+
case "save":
|
|
26
|
+
return saveTemplate(args[1]);
|
|
27
|
+
case "delete":
|
|
28
|
+
return deleteTemplate(args[1]);
|
|
29
|
+
case "export":
|
|
30
|
+
return exportTemplate(args[1], args[2]);
|
|
31
|
+
case "import":
|
|
32
|
+
return importTemplate(args[1]);
|
|
33
|
+
default:
|
|
34
|
+
console.log(`
|
|
35
|
+
Usage: ulpi templates <subcommand>
|
|
36
|
+
|
|
37
|
+
Subcommands:
|
|
38
|
+
list List bundled and user templates
|
|
39
|
+
save Save current rules as a user template
|
|
40
|
+
delete Delete a user template
|
|
41
|
+
export Export a template to file
|
|
42
|
+
import Import a template from file
|
|
43
|
+
`.trim());
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
function listTemplates() {
|
|
47
|
+
console.log(chalk.bold("\nBundled Templates:\n"));
|
|
48
|
+
const bundled = loadBundledTemplates();
|
|
49
|
+
for (const t of bundled) {
|
|
50
|
+
console.log(` ${chalk.cyan(t.id.padEnd(25))} ${chalk.dim(t.category)} \u2014 ${t.name}`);
|
|
51
|
+
}
|
|
52
|
+
console.log(chalk.bold("\nUser Templates:\n"));
|
|
53
|
+
const userTemplates = listUserTemplates();
|
|
54
|
+
if (userTemplates.length === 0) {
|
|
55
|
+
console.log(chalk.dim(" No user templates saved."));
|
|
56
|
+
} else {
|
|
57
|
+
for (const t of userTemplates) {
|
|
58
|
+
console.log(` ${chalk.green(t.name.padEnd(25))} ${t.description ?? ""}`);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
console.log("");
|
|
62
|
+
}
|
|
63
|
+
function saveTemplate(name) {
|
|
64
|
+
if (!name) {
|
|
65
|
+
console.log(chalk.red("Usage: ulpi templates save <name>"));
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
const projectRulesPath = path.join(process.cwd(), ".ulpi", "guards.yml");
|
|
69
|
+
if (!fs.existsSync(projectRulesPath)) {
|
|
70
|
+
console.log(chalk.red("No guards.yml found in current project."));
|
|
71
|
+
console.log(chalk.dim("Run 'ulpi init' first to generate rules."));
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
const config = loadRulesSync(projectRulesPath);
|
|
75
|
+
if (!config) {
|
|
76
|
+
console.log(chalk.red("Failed to parse guards.yml"));
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
const extractRules = (section) => {
|
|
80
|
+
const result = {};
|
|
81
|
+
for (const [key, rule] of Object.entries(section)) {
|
|
82
|
+
const { id, type, ...rest } = rule;
|
|
83
|
+
result[key] = rest;
|
|
84
|
+
}
|
|
85
|
+
return result;
|
|
86
|
+
};
|
|
87
|
+
const template = {
|
|
88
|
+
name,
|
|
89
|
+
description: `Saved from ${config.project.name} on ${(/* @__PURE__ */ new Date()).toISOString().split("T")[0]}`,
|
|
90
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
91
|
+
stack: config.project,
|
|
92
|
+
layers: [],
|
|
93
|
+
// No bundled layer references since this is a custom save
|
|
94
|
+
rules: {
|
|
95
|
+
preconditions: extractRules(config.preconditions),
|
|
96
|
+
postconditions: extractRules(config.postconditions),
|
|
97
|
+
permissions: extractRules(config.permissions),
|
|
98
|
+
pipelines: extractRules(config.pipelines)
|
|
99
|
+
},
|
|
100
|
+
skills: []
|
|
101
|
+
// Could extract skill references from rules if needed
|
|
102
|
+
};
|
|
103
|
+
try {
|
|
104
|
+
saveUserTemplate(template);
|
|
105
|
+
console.log(chalk.green(`\u2713 Template "${name}" saved`));
|
|
106
|
+
console.log(chalk.dim(` Location: ~/.ulpi/templates/${name}.yml`));
|
|
107
|
+
console.log(chalk.dim(` Rules: ${Object.keys(config.preconditions).length} preconditions, ${Object.keys(config.permissions).length} permissions`));
|
|
108
|
+
} catch (err) {
|
|
109
|
+
console.log(chalk.red(`Failed to save template: ${err instanceof Error ? err.message : String(err)}`));
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
function deleteTemplate(id) {
|
|
113
|
+
if (!id) {
|
|
114
|
+
console.log(chalk.red("Usage: ulpi templates delete <id>"));
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
const deleted = deleteUserTemplate(id);
|
|
118
|
+
if (deleted) {
|
|
119
|
+
console.log(chalk.green(`\u2713 Template "${id}" deleted`));
|
|
120
|
+
} else {
|
|
121
|
+
console.log(chalk.red(`Template "${id}" not found`));
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
function exportTemplate(name, outputPath) {
|
|
125
|
+
if (!name) {
|
|
126
|
+
console.log(chalk.red("Usage: ulpi templates export <name> [output-path]"));
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
const exported = exportUserTemplate(name);
|
|
130
|
+
if (exported) {
|
|
131
|
+
if (outputPath) {
|
|
132
|
+
fs.writeFileSync(outputPath, exported, "utf-8");
|
|
133
|
+
console.log(chalk.green(`\u2713 Template "${name}" exported to ${outputPath}`));
|
|
134
|
+
} else {
|
|
135
|
+
console.log(exported);
|
|
136
|
+
}
|
|
137
|
+
} else {
|
|
138
|
+
console.log(chalk.red(`Template "${name}" not found`));
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
function importTemplate(inputPath) {
|
|
142
|
+
if (!inputPath) {
|
|
143
|
+
console.log(chalk.red("Usage: ulpi templates import <file-path>"));
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
try {
|
|
147
|
+
const content = fs.readFileSync(inputPath, "utf-8");
|
|
148
|
+
const imported = importUserTemplate(content);
|
|
149
|
+
console.log(chalk.green(`\u2713 Template imported as "${imported.name}"`));
|
|
150
|
+
} catch (err) {
|
|
151
|
+
console.log(chalk.red(`Failed to import template: ${err instanceof Error ? err.message : String(err)}`));
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
export {
|
|
155
|
+
runTemplates
|
|
156
|
+
};
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createApiServer,
|
|
3
|
+
setUiServerPort
|
|
4
|
+
} from "./chunk-Q4HIY43N.js";
|
|
5
|
+
import {
|
|
6
|
+
attachWebSocket
|
|
7
|
+
} from "./chunk-7AL4DOEJ.js";
|
|
8
|
+
import {
|
|
9
|
+
generateApiSecret,
|
|
10
|
+
setApiSecret
|
|
11
|
+
} from "./chunk-MIAQVCFW.js";
|
|
12
|
+
import "./chunk-2MZER6ND.js";
|
|
13
|
+
import "./chunk-3SBPZRB5.js";
|
|
14
|
+
import "./chunk-2CLNOKPA.js";
|
|
15
|
+
import "./chunk-SPOI23SB.js";
|
|
16
|
+
import "./chunk-6OCEY7JY.js";
|
|
17
|
+
import "./chunk-SIAQVRKG.js";
|
|
18
|
+
import "./chunk-NNUWU6CV.js";
|
|
19
|
+
import "./chunk-YM2HV4IA.js";
|
|
20
|
+
import "./chunk-KIKPIH6N.js";
|
|
21
|
+
import {
|
|
22
|
+
API_LOCK_FILE,
|
|
23
|
+
getApiHost,
|
|
24
|
+
getApiPort
|
|
25
|
+
} from "./chunk-7LXY5UVC.js";
|
|
26
|
+
import "./chunk-4VNS5WPM.js";
|
|
27
|
+
|
|
28
|
+
// src/commands/ui.ts
|
|
29
|
+
import chalk from "chalk";
|
|
30
|
+
|
|
31
|
+
// ../api/dist/index.js
|
|
32
|
+
import * as fs from "fs";
|
|
33
|
+
import * as path from "path";
|
|
34
|
+
function writeApiLockFile(port, secret) {
|
|
35
|
+
try {
|
|
36
|
+
const dir = path.dirname(API_LOCK_FILE);
|
|
37
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
38
|
+
const lockData = { port, pid: process.pid, startedAt: (/* @__PURE__ */ new Date()).toISOString() };
|
|
39
|
+
if (secret) lockData.secret = secret;
|
|
40
|
+
fs.writeFileSync(API_LOCK_FILE, JSON.stringify(lockData), { encoding: "utf-8", mode: 384 });
|
|
41
|
+
} catch {
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
function removeApiLockFile() {
|
|
45
|
+
try {
|
|
46
|
+
fs.unlinkSync(API_LOCK_FILE);
|
|
47
|
+
} catch {
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
async function main() {
|
|
51
|
+
const { getApiPort: getApiPort2, getApiHost: getApiHost2 } = await import("./dist-RKOGLK7R.js");
|
|
52
|
+
const { generateApiSecret: generateApiSecret2, setApiSecret: setApiSecret2 } = await import("./auth-PN7TMQHV-2W4ICG64.js");
|
|
53
|
+
const port = getApiPort2();
|
|
54
|
+
const host = getApiHost2();
|
|
55
|
+
const projectDir = process.argv[2] || process.cwd();
|
|
56
|
+
const secret = generateApiSecret2();
|
|
57
|
+
setApiSecret2(secret);
|
|
58
|
+
const { createApiServer: createApiServer2 } = await import("./server-MOYPE4SM-N7SE2AN7.js");
|
|
59
|
+
const { attachWebSocket: attachWebSocket2 } = await import("./server-X5P6WH2M-7K2RY34N.js");
|
|
60
|
+
const server = createApiServer2(projectDir);
|
|
61
|
+
const wss = attachWebSocket2(server, projectDir);
|
|
62
|
+
const shutdown = () => {
|
|
63
|
+
console.log("\nShutting down ULPI API server...");
|
|
64
|
+
removeApiLockFile();
|
|
65
|
+
for (const client of wss.clients) {
|
|
66
|
+
client.close();
|
|
67
|
+
}
|
|
68
|
+
wss.close();
|
|
69
|
+
server.close(() => {
|
|
70
|
+
console.log("Server stopped.");
|
|
71
|
+
process.exit(0);
|
|
72
|
+
});
|
|
73
|
+
setTimeout(() => process.exit(0), 5e3).unref();
|
|
74
|
+
};
|
|
75
|
+
process.on("SIGTERM", shutdown);
|
|
76
|
+
process.on("SIGINT", shutdown);
|
|
77
|
+
server.listen(port, host, () => {
|
|
78
|
+
writeApiLockFile(port, secret);
|
|
79
|
+
console.log(`ULPI API server running at http://${host}:${port}`);
|
|
80
|
+
console.log(` WebSocket: ws://${host}:${port}/ws`);
|
|
81
|
+
console.log(` API: http://${host}:${port}/api/health`);
|
|
82
|
+
console.log(` Project: ${projectDir}`);
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
var isDirectRun = process.argv[1] && (process.argv[1].endsWith("index.js") || process.argv[1].endsWith("index.mjs"));
|
|
86
|
+
if (isDirectRun) {
|
|
87
|
+
main().catch((err) => {
|
|
88
|
+
console.error(
|
|
89
|
+
"Fatal:",
|
|
90
|
+
err instanceof Error ? err.message : String(err)
|
|
91
|
+
);
|
|
92
|
+
process.exit(1);
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// src/commands/ui.ts
|
|
97
|
+
async function runUI(args, projectDir) {
|
|
98
|
+
const portIndex = args.indexOf("--port");
|
|
99
|
+
let port = getApiPort();
|
|
100
|
+
if (portIndex !== -1 && args[portIndex + 1]) {
|
|
101
|
+
const parsed = parseInt(args[portIndex + 1], 10);
|
|
102
|
+
if (isNaN(parsed) || parsed < 1 || parsed > 65535) {
|
|
103
|
+
console.log(chalk.red("Invalid port number. Must be between 1 and 65535."));
|
|
104
|
+
process.exit(1);
|
|
105
|
+
}
|
|
106
|
+
port = parsed;
|
|
107
|
+
}
|
|
108
|
+
const host = getApiHost();
|
|
109
|
+
try {
|
|
110
|
+
const secret = generateApiSecret();
|
|
111
|
+
setApiSecret(secret);
|
|
112
|
+
setUiServerPort(port);
|
|
113
|
+
const server = createApiServer(projectDir);
|
|
114
|
+
const wss = attachWebSocket(server, projectDir);
|
|
115
|
+
const shutdown = () => {
|
|
116
|
+
console.log("\nShutting down ULPI server...");
|
|
117
|
+
removeApiLockFile();
|
|
118
|
+
for (const client of wss.clients) {
|
|
119
|
+
client.close();
|
|
120
|
+
}
|
|
121
|
+
wss.close();
|
|
122
|
+
server.close(() => {
|
|
123
|
+
console.log("Server stopped.");
|
|
124
|
+
process.exit(0);
|
|
125
|
+
});
|
|
126
|
+
setTimeout(() => process.exit(0), 5e3).unref();
|
|
127
|
+
};
|
|
128
|
+
process.on("SIGTERM", shutdown);
|
|
129
|
+
process.on("SIGINT", shutdown);
|
|
130
|
+
await new Promise((resolve, reject) => {
|
|
131
|
+
server.on("error", (err) => {
|
|
132
|
+
if (err.code === "EADDRINUSE") {
|
|
133
|
+
console.error(
|
|
134
|
+
`Port ${port} is already in use. Try a different port with --port.`
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
reject(err);
|
|
138
|
+
});
|
|
139
|
+
server.listen(port, host, () => {
|
|
140
|
+
writeApiLockFile(port, secret);
|
|
141
|
+
console.log(`
|
|
142
|
+
ULPI server running at:
|
|
143
|
+
`);
|
|
144
|
+
console.log(` http://${host}:${port}
|
|
145
|
+
`);
|
|
146
|
+
console.log(` WebSocket: ws://${host}:${port}/ws`);
|
|
147
|
+
console.log(` API: http://${host}:${port}/api/rules
|
|
148
|
+
`);
|
|
149
|
+
console.log(`Project dir: ${projectDir}
|
|
150
|
+
`);
|
|
151
|
+
console.log(`Press Ctrl+C to stop.
|
|
152
|
+
`);
|
|
153
|
+
resolve();
|
|
154
|
+
});
|
|
155
|
+
});
|
|
156
|
+
} catch (err) {
|
|
157
|
+
console.error(
|
|
158
|
+
chalk.red(
|
|
159
|
+
`Failed to start UI server: ${err instanceof Error ? err.message : String(err)}`
|
|
160
|
+
)
|
|
161
|
+
);
|
|
162
|
+
process.exit(1);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
export {
|
|
166
|
+
runUI
|
|
167
|
+
};
|