@memberjunction/cli 6.2.0-edge.4 → 6.2.0-edge.6
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 +22 -0
- package/dist/commands/agent/init.d.ts +5 -0
- package/dist/commands/agent/init.d.ts.map +1 -1
- package/dist/commands/agent/init.js +109 -0
- package/dist/commands/agent/init.js.map +1 -1
- package/dist/commands/ai/actions/run.d.ts.map +1 -1
- package/dist/commands/ai/actions/run.js +5 -1
- package/dist/commands/ai/actions/run.js.map +1 -1
- package/dist/commands/ai/agents/run.d.ts +1 -0
- package/dist/commands/ai/agents/run.d.ts.map +1 -1
- package/dist/commands/ai/agents/run.js +20 -6
- package/dist/commands/ai/agents/run.js.map +1 -1
- package/dist/commands/ai/prompts/run.d.ts.map +1 -1
- package/dist/commands/ai/prompts/run.js +5 -1
- package/dist/commands/ai/prompts/run.js.map +1 -1
- package/dist/commands/app/install.d.ts.map +1 -1
- package/dist/commands/app/install.js +17 -2
- package/dist/commands/app/install.js.map +1 -1
- package/dist/commands/app/upgrade.d.ts.map +1 -1
- package/dist/commands/app/upgrade.js +7 -1
- package/dist/commands/app/upgrade.js.map +1 -1
- package/dist/commands/dbdoc/analyze.d.ts +1 -0
- package/dist/commands/dbdoc/analyze.d.ts.map +1 -1
- package/dist/commands/dbdoc/analyze.js +7 -0
- package/dist/commands/dbdoc/analyze.js.map +1 -1
- package/dist/commands/dbdoc/export.d.ts +6 -0
- package/dist/commands/dbdoc/export.d.ts.map +1 -1
- package/dist/commands/dbdoc/export.js +32 -0
- package/dist/commands/dbdoc/export.js.map +1 -1
- package/dist/commands/sync/watch.d.ts.map +1 -1
- package/dist/commands/sync/watch.js +3 -5
- package/dist/commands/sync/watch.js.map +1 -1
- package/dist/init-templates/citizen-builder/.agents/skills/new-agent/SKILL.md +19 -6
- package/dist/init-templates/citizen-builder/.agents/skills/test-agent/SKILL.md +4 -1
- package/dist/init-templates/citizen-builder/.claude/skills/new-agent/SKILL.md +19 -6
- package/dist/init-templates/citizen-builder/.claude/skills/test-agent/SKILL.md +4 -1
- package/dist/init-templates/citizen-builder/.env.example +4 -2
- package/dist/init-templates/citizen-builder/AGENTS.md +136 -40
- package/dist/init-templates/citizen-builder/README.md +18 -5
- package/dist/init-templates/citizen-builder/docker-compose.yml +6 -5
- package/dist/init-templates/citizen-builder/metadata/.mj-sync.json +7 -4
- package/dist/init-templates/citizen-builder/metadata/agents/.customer-insight-agent.json +17 -13
- package/dist/init-templates/citizen-builder/metadata/prompts/.customer-insight-prompt.json +3 -1
- package/dist/init-templates/citizen-builder/metadata/prompts/templates/customer-insight.template.md +8 -0
- package/dist/init-templates/citizen-builder/scripts/docker-entrypoint.sh +140 -38
- package/dist/init-templates/citizen-builder/scripts/sync-metadata.sh +1 -1
- package/dist/lib/dev-workspace/build.d.ts.map +1 -1
- package/dist/lib/dev-workspace/build.js +43 -11
- package/dist/lib/dev-workspace/build.js.map +1 -1
- package/dist/lib/dev-workspace/types.d.ts +9 -5
- package/dist/lib/dev-workspace/types.d.ts.map +1 -1
- package/oclif.manifest.json +864 -791
- package/package.json +26 -26
|
@@ -6,6 +6,16 @@
|
|
|
6
6
|
|
|
7
7
|
---
|
|
8
8
|
|
|
9
|
+
## 📋 Before You Start (Prerequisites)
|
|
10
|
+
|
|
11
|
+
1. **Docker Desktop** installed and running ([Download Docker Desktop](https://www.docker.com/products/docker-desktop)):
|
|
12
|
+
- Allocate at least **8–12 GB of RAM** to Docker Desktop in **Settings → Resources** (SQL Server + MJAPI + MJExplorer run together inside the container stack).
|
|
13
|
+
2. **Node.js 20+** installed on your machine ([Download Node.js](https://nodejs.org/)) — required only if you run `npx @memberjunction/cli agent init` directly on your host machine.
|
|
14
|
+
3. **One LLM API Key** (OpenAI, Anthropic, Google Gemini, Groq, or Mistral).
|
|
15
|
+
4. **Windows / PowerShell Note**: When running headless test prompts with quotes or multiple lines on Windows PowerShell, pass `-f /work/<prompt-file.txt>` (`--prompt-file`) to `mj ai agents run` instead of inline `-p "..."` strings to avoid PowerShell quote stripping.
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
9
19
|
## ⚡ Getting Started (Choose Your Path)
|
|
10
20
|
|
|
11
21
|
### Option A: The Agent-Driven Path (Recommended — Zero Manual Setup)
|
|
@@ -63,8 +73,8 @@ The **Citizen Agent Builder** provides an isolated, local MemberJunction environ
|
|
|
63
73
|
* **`sqlserver` (Port 1433)**: Microsoft SQL Server 2022.
|
|
64
74
|
* **`mj` (Ports 4000 & 4202)**: A Node 24 container that executes `mj install` on first boot, provisions the database schema, installs business context (More Cheese default, or enterprise apps like Blue Cypress), and serves:
|
|
65
75
|
* **MJAPI** at `http://localhost:4000` (GraphQL API and agent execution engine).
|
|
66
|
-
* **MJExplorer** at `http://localhost:4202` (Web UI for testing agents and viewing records; port 4202 is an authorized redirect URI for Auth0/MSAL).
|
|
67
|
-
* **Metadata Directory (`./metadata`)**: Local JSON and Markdown files mapped into the container. Pushing metadata to the database is done with a single command (`./scripts/sync-metadata.sh`).
|
|
76
|
+
* **MJExplorer** at `http://localhost:4202` (Web UI for testing agents and viewing records; zero-config Local Dev Auth is enabled by default on localhost, and port 4202 is also an authorized redirect URI for Auth0/MSAL).
|
|
77
|
+
* **Metadata Directory (`./metadata`)**: Local JSON and Markdown files mapped into the container. Pushing metadata to the database is done with a single command (`./scripts/sync-metadata.sh`, which runs `mj sync push --dir /work/metadata`).
|
|
68
78
|
|
|
69
79
|
### Available Agent Tools & CLI Commands
|
|
70
80
|
|
|
@@ -151,7 +161,8 @@ Always enforce these constraints when authoring agents:
|
|
|
151
161
|
1. **`ModelSelectionMode: "Agent Type"`**: Never hardcode specific provider models (`gpt-4o`, `claude-3-5-sonnet`). The destination environment maps models to Agent Types.
|
|
152
162
|
2. **`ExposeAsAction: false`**: Do not set `true` unless the user explicitly wants other agents to call this agent as an action.
|
|
153
163
|
3. **Dynamic Record Resolution**: Never hardcode record IDs or personal names. Use queries, parameters, or lookup actions.
|
|
154
|
-
4. **Prefer `
|
|
164
|
+
4. **Prefer `Loop` Agents by Default**: Use `Loop` agents (`@lookup:MJ: AI Agent Types.Name=Loop`) for interactive, conversational, and exploratory Citizen Builder agents where the agent calls actions/tools and responds to the user. Use `Flow` agents (`@lookup:MJ: AI Agent Types.Name=Flow`) only when you want a fixed, non-interactive deterministic step graph.
|
|
165
|
+
5. **`ArtifactCreationMode: "Never"`**: Valid values are `"Never"`, `"Always"`, or `"System Only"` (never `"None"`).
|
|
155
166
|
|
|
156
167
|
---
|
|
157
168
|
|
|
@@ -165,7 +176,7 @@ Always enforce these constraints when authoring agents:
|
|
|
165
176
|
* **No `sync` Blocks**: Do not author `sync` blocks (`lastModified`, `checksum`). `mj sync push` manages these automatically.
|
|
166
177
|
* **Assign Deterministic UUIDs**: Assign a fresh uppercase UUID for `primaryKey` (e.g. via CLI `uuidgen | tr '[:lower:]' '[:upper:]'`).
|
|
167
178
|
* **Use Dynamic References**:
|
|
168
|
-
- `@lookup:<EntityName>.<FieldName>=<Value>` for foreign keys (e.g. `@lookup:MJ: AI Agent Types.Name=
|
|
179
|
+
- `@lookup:<EntityName>.<FieldName>=<Value>` for foreign keys (e.g. `@lookup:MJ: AI Agent Types.Name=Loop`).
|
|
169
180
|
- `@file:<relativePath>` for external template files (e.g. `@file:templates/<slug>.template.md`). Note that `@file:` paths are resolved at push time; running `./scripts/sync-metadata.sh` updates the database.
|
|
170
181
|
- `@parent:ID` for linking child records to parent records in nested structures.
|
|
171
182
|
|
|
@@ -173,7 +184,7 @@ Always enforce these constraints when authoring agents:
|
|
|
173
184
|
* Prompt Markdown template: `metadata/prompts/templates/<slug>.template.md`
|
|
174
185
|
* Prompt metadata JSON: `metadata/prompts/.<slug>-prompt.json`
|
|
175
186
|
* Agent metadata JSON: `metadata/agents/.<slug>-agent.json`
|
|
176
|
-
*(See `metadata/agents/.customer-insight-agent.json` for a reference
|
|
187
|
+
*(See `metadata/agents/.customer-insight-agent.json` for a reference Loop agent).*
|
|
177
188
|
|
|
178
189
|
4. **Push to Local Database**:
|
|
179
190
|
```bash
|
|
@@ -191,6 +202,8 @@ Always enforce these constraints when authoring agents:
|
|
|
191
202
|
You can trigger test runs directly via CLI with structured output:
|
|
192
203
|
```bash
|
|
193
204
|
docker compose exec -T mj mj ai agents run -a "<Agent Name>" -p "<Test Input>" --format json
|
|
205
|
+
# On Windows PowerShell or with multi-line inputs, pass a file via -f (--prompt-file):
|
|
206
|
+
docker compose exec -T mj mj ai agents run -a "<Agent Name>" -f /work/test-input.txt --format json
|
|
194
207
|
```
|
|
195
208
|
|
|
196
209
|
3. **Diagnosing Errors & Auditing Execution Traces**:
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
name: mj-citizen-builder
|
|
1
|
+
name: ${COMPOSE_PROJECT_NAME:-mj-citizen-builder}
|
|
2
2
|
|
|
3
3
|
services:
|
|
4
4
|
sqlserver:
|
|
@@ -9,7 +9,7 @@ services:
|
|
|
9
9
|
ACCEPT_EULA: "Y"
|
|
10
10
|
MSSQL_SA_PASSWORD: "${DB_PASSWORD:-TestPassword123!}"
|
|
11
11
|
ports:
|
|
12
|
-
- "
|
|
12
|
+
- "127.0.0.1:${DB_PORT:-1433}:1433"
|
|
13
13
|
healthcheck:
|
|
14
14
|
test: /opt/mssql-tools18/bin/sqlcmd -S localhost -U sa -P "$$MSSQL_SA_PASSWORD" -Q "SELECT 1" -C -No
|
|
15
15
|
interval: 10s
|
|
@@ -33,8 +33,8 @@ services:
|
|
|
33
33
|
sqlserver:
|
|
34
34
|
condition: service_healthy
|
|
35
35
|
ports:
|
|
36
|
-
- "
|
|
37
|
-
- "
|
|
36
|
+
- "127.0.0.1:${API_PORT:-4000}:4000"
|
|
37
|
+
- "127.0.0.1:${EXPLORER_PORT:-4202}:4200"
|
|
38
38
|
environment:
|
|
39
39
|
DB_HOST: "sqlserver"
|
|
40
40
|
DB_PORT: "1433"
|
|
@@ -43,7 +43,8 @@ services:
|
|
|
43
43
|
DB_DATABASE: "${DB_DATABASE:-MemberJunction}"
|
|
44
44
|
# Tells the entrypoint which MemberJunction release `mj install` must fetch
|
|
45
45
|
MJ_VERSION: "${MJ_VERSION}"
|
|
46
|
-
MJ_BASE_ENCRYPTION_KEY: "${MJ_BASE_ENCRYPTION_KEY:-
|
|
46
|
+
MJ_BASE_ENCRYPTION_KEY: "${MJ_BASE_ENCRYPTION_KEY:-MDEyMzQ1Njc4OWFiY2RlZjAxMjM0NTY3ODlhYmNkZWY=}"
|
|
47
|
+
MJ_DEV_AUTH_ENABLED: "${MJ_DEV_AUTH_ENABLED:-true}"
|
|
47
48
|
# LLM Provider API Keys
|
|
48
49
|
AI_VENDOR_API_KEY__OpenAILLM: "${OPENAI_API_KEY:-}"
|
|
49
50
|
AI_VENDOR_API_KEY__AnthropicLLM: "${ANTHROPIC_API_KEY:-}"
|
|
@@ -3,13 +3,13 @@
|
|
|
3
3
|
"fields": {
|
|
4
4
|
"Name": "Customer Insight Specialist",
|
|
5
5
|
"CategoryID": "@lookup:MJ: AI Agent Categories.Name=Assistant",
|
|
6
|
-
"Description": "
|
|
7
|
-
"TypeID": "@lookup:MJ: AI Agent Types.Name=
|
|
6
|
+
"Description": "Interactive Loop agent that summarizes customer activity, evaluates account standing, and suggests next actions.",
|
|
7
|
+
"TypeID": "@lookup:MJ: AI Agent Types.Name=Loop",
|
|
8
8
|
"Status": "Active",
|
|
9
9
|
"ExecutionOrder": 0,
|
|
10
10
|
"ExposeAsAction": false,
|
|
11
11
|
"IconClass": "mj-icon-user-check",
|
|
12
|
-
"ArtifactCreationMode": "
|
|
12
|
+
"ArtifactCreationMode": "Never",
|
|
13
13
|
"PayloadDownstreamPaths": "*",
|
|
14
14
|
"PayloadUpstreamPaths": "*",
|
|
15
15
|
"EnableContextCompression": false,
|
|
@@ -22,29 +22,33 @@
|
|
|
22
22
|
"AgentID": "@parent:ID",
|
|
23
23
|
"PromptID": "@lookup:MJ: AI Prompts.Name=Customer Insight Specialist Prompt",
|
|
24
24
|
"Status": "Active",
|
|
25
|
-
"ExecutionOrder":
|
|
25
|
+
"ExecutionOrder": 0
|
|
26
26
|
},
|
|
27
27
|
"primaryKey": {
|
|
28
28
|
"ID": "E9A0C381-645F-4D2A-883F-E19C69D3B511"
|
|
29
29
|
}
|
|
30
30
|
}
|
|
31
31
|
],
|
|
32
|
-
"MJ: AI Agent
|
|
32
|
+
"MJ: AI Agent Actions": [
|
|
33
33
|
{
|
|
34
34
|
"fields": {
|
|
35
35
|
"AgentID": "@parent:ID",
|
|
36
|
-
"
|
|
37
|
-
"
|
|
38
|
-
"StepType": "Prompt",
|
|
39
|
-
"StartingStep": true,
|
|
40
|
-
"PromptID": "@lookup:MJ: AI Prompts.Name=Customer Insight Specialist Prompt",
|
|
41
|
-
"Status": "Active",
|
|
42
|
-
"PositionX": 100,
|
|
43
|
-
"PositionY": 100
|
|
36
|
+
"ActionID": "@lookup:MJ: Actions.Name=Run Ad-hoc Query",
|
|
37
|
+
"Status": "Active"
|
|
44
38
|
},
|
|
45
39
|
"primaryKey": {
|
|
46
40
|
"ID": "D2E49B18-091A-4832-B81E-A38C91307D55"
|
|
47
41
|
}
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
"fields": {
|
|
45
|
+
"AgentID": "@parent:ID",
|
|
46
|
+
"ActionID": "@lookup:MJ: Actions.Name=Run Stored Query",
|
|
47
|
+
"Status": "Active"
|
|
48
|
+
},
|
|
49
|
+
"primaryKey": {
|
|
50
|
+
"ID": "C8B29A14-312E-4981-9B1F-55913A7C2044"
|
|
51
|
+
}
|
|
48
52
|
}
|
|
49
53
|
]
|
|
50
54
|
},
|
|
@@ -2,8 +2,10 @@
|
|
|
2
2
|
{
|
|
3
3
|
"fields": {
|
|
4
4
|
"Name": "Customer Insight Specialist Prompt",
|
|
5
|
-
"Description": "Analyzes customer profile data and recent
|
|
5
|
+
"Description": "System prompt for the Customer Insight Specialist agent. Analyzes customer profile data and recent activity to provide executive account insights.",
|
|
6
6
|
"CategoryID": "@lookup:MJ: AI Prompt Categories.Name=Agent Type System Prompts",
|
|
7
|
+
"PromptRole": "System",
|
|
8
|
+
"PromptPosition": "First",
|
|
7
9
|
"TypeID": "@lookup:MJ: AI Prompt Types.Name=Chat",
|
|
8
10
|
"Status": "Active",
|
|
9
11
|
"TemplateText": "@file:templates/customer-insight.template.md"
|
package/dist/init-templates/citizen-builder/metadata/prompts/templates/customer-insight.template.md
CHANGED
|
@@ -2,6 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
You are an expert customer account analyst. Your goal is to review customer profile data and order history, then synthesize a concise executive summary with actionable recommendations.
|
|
4
4
|
|
|
5
|
+
## User Request
|
|
6
|
+
{{ userMessage }}
|
|
7
|
+
|
|
8
|
+
## Available Payload Data
|
|
9
|
+
```json
|
|
10
|
+
{{ payload | dump(2) }}
|
|
11
|
+
```
|
|
12
|
+
|
|
5
13
|
## Instructions
|
|
6
14
|
1. Analyze the customer account details, active status, and recent activity.
|
|
7
15
|
2. Review any open orders or pending balances.
|
|
@@ -58,31 +58,37 @@ if [ ! -f "$STATE_DIR/provisioned" ]; then
|
|
|
58
58
|
echo "========================================================================"
|
|
59
59
|
|
|
60
60
|
if [ ! -f "$STATE_DIR/core-installed" ]; then
|
|
61
|
-
# Generate install configuration
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
}
|
|
85
|
-
|
|
61
|
+
# Generate install configuration safely via JSON.stringify so special characters in passwords/keys are escaped
|
|
62
|
+
node -e "
|
|
63
|
+
const fs = require('fs');
|
|
64
|
+
const cfg = {
|
|
65
|
+
PackageManager: 'pnpm',
|
|
66
|
+
DatabaseHost: process.env.DB_HOST || 'sqlserver',
|
|
67
|
+
DatabasePort: Number(process.env.DB_PORT || 1433),
|
|
68
|
+
DatabaseName: process.env.DB_DATABASE || 'MemberJunction',
|
|
69
|
+
DatabaseTrustCert: true,
|
|
70
|
+
DatabaseAdminUser: 'sa',
|
|
71
|
+
DatabaseAdminPassword: process.env.DB_PASSWORD || '',
|
|
72
|
+
CodeGenUser: 'sa',
|
|
73
|
+
CodeGenPassword: process.env.DB_PASSWORD || '',
|
|
74
|
+
APIUser: 'sa',
|
|
75
|
+
APIPassword: process.env.DB_PASSWORD || '',
|
|
76
|
+
APIPort: 4000,
|
|
77
|
+
AuthProvider: 'local',
|
|
78
|
+
BaseEncryptionKey: process.env.MJ_BASE_ENCRYPTION_KEY || 'MDEyMzQ1Njc4OWFiY2RlZjAxMjM0NTY3ODlhYmNkZWY=',
|
|
79
|
+
CreateNewUser: {
|
|
80
|
+
Username: 'admin',
|
|
81
|
+
Email: 'admin@memberjunction.org',
|
|
82
|
+
FirstName: 'Admin',
|
|
83
|
+
LastName: 'User'
|
|
84
|
+
},
|
|
85
|
+
OpenAIKey: process.env.AI_VENDOR_API_KEY__OpenAILLM || '',
|
|
86
|
+
AnthropicKey: process.env.AI_VENDOR_API_KEY__AnthropicLLM || '',
|
|
87
|
+
GeminiKey: process.env.AI_VENDOR_API_KEY__GeminiLLM || '',
|
|
88
|
+
MistralKey: process.env.AI_VENDOR_API_KEY__MistralLLM || ''
|
|
89
|
+
};
|
|
90
|
+
fs.writeFileSync('/tmp/install.config.json', JSON.stringify(cfg, null, 2), { mode: 0o600 });
|
|
91
|
+
"
|
|
86
92
|
|
|
87
93
|
# Install the release this workspace is pinned to (MJ_VERSION, the same release as the CLI
|
|
88
94
|
# in this container). Without a tag, `mj install --yes` takes the newest stable GitHub
|
|
@@ -96,20 +102,17 @@ EOF
|
|
|
96
102
|
|
|
97
103
|
# Execute headless install. Safe to retry: the installer checkpoints completed phases.
|
|
98
104
|
mj install --yes --fast --config /tmp/install.config.json --dir /workspace "${INSTALL_TAG_ARGS[@]}"
|
|
105
|
+
rm -f /tmp/install.config.json
|
|
99
106
|
touch "$STATE_DIR/core-installed"
|
|
100
107
|
pnpm add -w @angular/compiler@21.2.22 2>/dev/null || true
|
|
101
108
|
fi
|
|
102
109
|
|
|
103
110
|
# Install Open App business context (More Cheese default or custom enterprise app)
|
|
111
|
+
# Note: GITHUB_TOKEN is read directly from the environment by OpenAppEngine's GitHubClient
|
|
104
112
|
if [ ! -f "$STATE_DIR/app-installed" ]; then
|
|
105
113
|
APP_URL="${OPEN_APP_INSTALL_URL:-https://github.com/MemberJunction/more-cheese}"
|
|
106
114
|
echo "Installing business context Open App: $APP_URL..."
|
|
107
|
-
|
|
108
|
-
AUTH_APP_URL=$(echo "$APP_URL" | sed -E "s|https://github.com/|https://$GITHUB_TOKEN@github.com/|")
|
|
109
|
-
mj app install "$AUTH_APP_URL"
|
|
110
|
-
else
|
|
111
|
-
mj app install "$APP_URL"
|
|
112
|
-
fi
|
|
115
|
+
mj app install "$APP_URL"
|
|
113
116
|
touch "$STATE_DIR/app-installed"
|
|
114
117
|
fi
|
|
115
118
|
|
|
@@ -120,8 +123,8 @@ EOF
|
|
|
120
123
|
|| echo "WARNING: capabilities catalog generation failed, so the catalog may be missing or stale. Re-run scripts/generate-capabilities.sh."
|
|
121
124
|
fi
|
|
122
125
|
|
|
123
|
-
# Push starter metadata. --ci: never prompt (there is no terminal here)
|
|
124
|
-
#
|
|
126
|
+
# Push starter metadata. --ci: never prompt (there is no terminal here), create
|
|
127
|
+
# Template records for @file: prompt templates on first push, and exit non-zero on error.
|
|
125
128
|
if [ -d "/work/metadata" ]; then
|
|
126
129
|
mj sync push --dir /work/metadata --ci
|
|
127
130
|
fi
|
|
@@ -156,10 +159,82 @@ if [ -f "apps/MJExplorer/package.json" ]; then
|
|
|
156
159
|
"
|
|
157
160
|
fi
|
|
158
161
|
|
|
162
|
+
# Ensure turbo.json passes through AI vendor API keys, DB settings, and MJ_DEV_AUTH_ENABLED to child processes
|
|
163
|
+
if [ -f "turbo.json" ]; then
|
|
164
|
+
node -e "
|
|
165
|
+
const fs = require('fs');
|
|
166
|
+
try {
|
|
167
|
+
const turbo = JSON.parse(fs.readFileSync('turbo.json', 'utf8'));
|
|
168
|
+
const passThrough = new Set(turbo.globalPassThroughEnv || []);
|
|
169
|
+
let changed = false;
|
|
170
|
+
for (const entry of ['AI_VENDOR_API_KEY__*', 'MJ_*', 'DB_*', 'CODEGEN_DB_*', 'GRAPHQL_*', 'OPEN_APP_*', 'GITHUB_TOKEN']) {
|
|
171
|
+
if (!passThrough.has(entry)) {
|
|
172
|
+
passThrough.add(entry);
|
|
173
|
+
changed = true;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
if (changed) {
|
|
177
|
+
turbo.globalPassThroughEnv = Array.from(passThrough);
|
|
178
|
+
fs.writeFileSync('turbo.json', JSON.stringify(turbo, null, 2) + '\n');
|
|
179
|
+
}
|
|
180
|
+
} catch (e) {
|
|
181
|
+
console.warn('Notice: turbo.json check skipped:', e.message);
|
|
182
|
+
}
|
|
183
|
+
"
|
|
184
|
+
fi
|
|
185
|
+
|
|
186
|
+
# Sync container environment variables (API keys, encryption key, DB_USER, local dev auth) into workspace .env files
|
|
187
|
+
export MJ_DEV_AUTH_ENABLED="${MJ_DEV_AUTH_ENABLED:-true}"
|
|
188
|
+
node -e "
|
|
189
|
+
const fs = require('fs');
|
|
190
|
+
const upsertVar = (content, key, val) => {
|
|
191
|
+
const re = new RegExp('^' + key + '=.*$', 'm');
|
|
192
|
+
const line = key + '=' + JSON.stringify(String(val));
|
|
193
|
+
if (re.test(content)) return content.replace(re, () => line);
|
|
194
|
+
return content + (content.endsWith('\n') ? '' : '\n') + line + '\n';
|
|
195
|
+
};
|
|
196
|
+
const keysToSync = [
|
|
197
|
+
'DB_HOST', 'DB_PORT', 'DB_DATABASE', 'DB_USERNAME', 'DB_PASSWORD',
|
|
198
|
+
'MJ_BASE_ENCRYPTION_KEY', 'MJ_DEV_AUTH_ENABLED',
|
|
199
|
+
'AI_VENDOR_API_KEY__OpenAILLM', 'AI_VENDOR_API_KEY__AnthropicLLM',
|
|
200
|
+
'AI_VENDOR_API_KEY__GeminiLLM', 'AI_VENDOR_API_KEY__GroqLLM', 'AI_VENDOR_API_KEY__MistralLLM'
|
|
201
|
+
];
|
|
202
|
+
for (const envFile of ['.env', 'apps/MJAPI/.env', 'packages/MJAPI/.env']) {
|
|
203
|
+
if (fs.existsSync(envFile)) {
|
|
204
|
+
let content = fs.readFileSync(envFile, 'utf8');
|
|
205
|
+
for (const k of keysToSync) {
|
|
206
|
+
const v = process.env[k];
|
|
207
|
+
if (v !== undefined && v !== '') {
|
|
208
|
+
content = upsertVar(content, k, v);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
content = upsertVar(content, 'DB_USER', process.env.DB_USERNAME || 'sa');
|
|
212
|
+
fs.writeFileSync(envFile, content);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
if (process.env.MJ_DEV_AUTH_ENABLED === 'true') {
|
|
216
|
+
for (const ngEnv of [
|
|
217
|
+
'apps/MJExplorer/src/environments/environment.ts',
|
|
218
|
+
'apps/MJExplorer/src/environments/environment.development.ts',
|
|
219
|
+
'packages/MJExplorer/src/environments/environment.ts',
|
|
220
|
+
'packages/MJExplorer/src/environments/environment.development.ts',
|
|
221
|
+
]) {
|
|
222
|
+
if (fs.existsSync(ngEnv)) {
|
|
223
|
+
const src = fs.readFileSync(ngEnv, 'utf8');
|
|
224
|
+
const next = src.replace(/AUTH_TYPE:\s*['\"][^'\"]*['\"]/g, \"AUTH_TYPE: 'local'\");
|
|
225
|
+
if (next !== src) {
|
|
226
|
+
fs.writeFileSync(ngEnv, next);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
"
|
|
232
|
+
|
|
159
233
|
# Sanitize dynamicPackages.client so non-browser packages are not bundled into MJExplorer
|
|
160
234
|
if [ -f "mj.config.cjs" ]; then
|
|
161
235
|
node -e "
|
|
162
236
|
const fs = require('fs');
|
|
237
|
+
const vm = require('vm');
|
|
163
238
|
try {
|
|
164
239
|
const config = require('./mj.config.cjs');
|
|
165
240
|
if (config.dynamicPackages && Array.isArray(config.dynamicPackages.client)) {
|
|
@@ -173,10 +248,37 @@ if [ -f "mj.config.cjs" ]; then
|
|
|
173
248
|
}
|
|
174
249
|
});
|
|
175
250
|
if (changed) {
|
|
176
|
-
|
|
177
|
-
const
|
|
178
|
-
|
|
179
|
-
|
|
251
|
+
const code = fs.readFileSync('mj.config.cjs', 'utf8');
|
|
252
|
+
const dynMatch = code.match(/dynamicPackages\s*:\s*\{/);
|
|
253
|
+
if (dynMatch && dynMatch.index !== undefined) {
|
|
254
|
+
const afterDyn = code.slice(dynMatch.index);
|
|
255
|
+
const clientRel = afterDyn.match(/client\s*:\s*\[/);
|
|
256
|
+
if (clientRel && clientRel.index !== undefined) {
|
|
257
|
+
const openPos = dynMatch.index + clientRel.index + clientRel[0].length - 1;
|
|
258
|
+
let depth = 1, pos = openPos + 1, inStr = null;
|
|
259
|
+
while (pos < code.length && depth > 0) {
|
|
260
|
+
const ch = code[pos];
|
|
261
|
+
if (inStr) {
|
|
262
|
+
if (ch === '\\\\') { pos += 2; continue; }
|
|
263
|
+
if (ch === inStr) inStr = null;
|
|
264
|
+
} else if (ch === '\"' || ch === \"'\" || ch === '\`') {
|
|
265
|
+
inStr = ch;
|
|
266
|
+
} else if (ch === '[') {
|
|
267
|
+
depth++;
|
|
268
|
+
} else if (ch === ']') {
|
|
269
|
+
depth--;
|
|
270
|
+
}
|
|
271
|
+
pos++;
|
|
272
|
+
}
|
|
273
|
+
if (depth === 0) {
|
|
274
|
+
const closePos = pos - 1;
|
|
275
|
+
const serialized = JSON.stringify(config.dynamicPackages.client, null, 2).replace(/\n/g, '\n ');
|
|
276
|
+
const updated = code.slice(0, openPos) + serialized + code.slice(closePos + 1);
|
|
277
|
+
vm.compileFunction(updated);
|
|
278
|
+
fs.writeFileSync('mj.config.cjs', updated);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
}
|
|
180
282
|
}
|
|
181
283
|
}
|
|
182
284
|
} catch (e) {
|
|
@@ -212,7 +314,7 @@ fi
|
|
|
212
314
|
echo "========================================================================"
|
|
213
315
|
echo " 🎉 MemberJunction Stack is Running!"
|
|
214
316
|
echo " MJAPI: http://localhost:4000 (GraphQL & API)"
|
|
215
|
-
echo " MJExplorer: http://localhost:4200 (Web Interface)"
|
|
317
|
+
echo " MJExplorer: http://localhost:4200 (Web Interface — Zero-Config Local Dev Auth active)"
|
|
216
318
|
echo " Database: localhost:$DB_PORT (DB: $DB_DATABASE)"
|
|
217
319
|
echo "========================================================================"
|
|
218
320
|
|
|
@@ -9,6 +9,6 @@ DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
|
9
9
|
cd "$DIR"
|
|
10
10
|
|
|
11
11
|
echo "Pushing metadata changes to MemberJunction database..."
|
|
12
|
-
docker compose exec -T mj mj sync push --dir /work/metadata
|
|
12
|
+
docker compose exec -T mj mj sync push --dir /work/metadata "$@"
|
|
13
13
|
|
|
14
14
|
echo "Metadata sync complete!"
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../../src/lib/dev-workspace/build.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../../src/lib/dev-workspace/build.ts"],"names":[],"mappings":"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"}
|
|
@@ -552,6 +552,13 @@ export function IndexWorkspacePackages(members) {
|
|
|
552
552
|
* contract `readJsonFile` already sets ("Unparseable JSON at <path>"). Without it a missing `name`
|
|
553
553
|
* surfaced as `Cannot read properties of undefined (reading 'length')`, which names neither the
|
|
554
554
|
* repo nor the file — and a developer may have a dozen of them.
|
|
555
|
+
*
|
|
556
|
+
* Also validates `platform`, when present, against the same three literals `runsInBrowser` below
|
|
557
|
+
* understands. `MjAppPackageEntry.platform` is a closed three-literal union, so the final
|
|
558
|
+
* `declared as MjAppPackageEntry[]` cast is a LIE unless this loop enforces it — an unvalidated
|
|
559
|
+
* typo like `"platform": "Node"` would satisfy the cast, fail every `=== 'node'`/`'browser'`/`'both'`
|
|
560
|
+
* comparison in `runsInBrowser`, and silently fall through its Node-only branch, dropping the
|
|
561
|
+
* package from the shell import set with no error (#4428).
|
|
555
562
|
*/
|
|
556
563
|
function readDeclaredEntries(member, section) {
|
|
557
564
|
const declared = member.MjAppJson?.packages?.[section];
|
|
@@ -568,33 +575,58 @@ function readDeclaredEntries(member, section) {
|
|
|
568
575
|
if (typeof entry.name !== 'string') {
|
|
569
576
|
throw new Error(`${where}[${index}] has no "name" string — a package entry must name its package`);
|
|
570
577
|
}
|
|
578
|
+
const platform = entry.platform;
|
|
579
|
+
if (platform !== undefined && !VALID_PLATFORMS.includes(platform)) {
|
|
580
|
+
throw new Error(`${where}[${index}] has an invalid "platform" value ${JSON.stringify(platform)} — must be one of ${VALID_PLATFORMS.join(', ')}`);
|
|
581
|
+
}
|
|
571
582
|
}
|
|
572
583
|
return declared;
|
|
573
584
|
}
|
|
585
|
+
/** The only valid values for a manifest package entry's `platform` field — see {@link runsInBrowser}. */
|
|
586
|
+
const VALID_PLATFORMS = ['node', 'browser', 'both'];
|
|
574
587
|
/**
|
|
575
588
|
* Every package a member declares that an app shell will be asked to import.
|
|
576
589
|
*
|
|
577
590
|
* This set mirrors the HOST's rule exactly, because the host is the only thing that decides what
|
|
578
591
|
* the shell imports. `GetClientPackagesFromManifest`
|
|
579
592
|
* (`packages/OpenApp/Engine/src/install/config-manager.ts`) builds the client dynamic-package list
|
|
580
|
-
* as `[...packages.client, ...packages.shared]`
|
|
581
|
-
*
|
|
582
|
-
*
|
|
583
|
-
* an import in the shell's generated class-registrations manifest, with no role field even present
|
|
584
|
-
* on its entry type.
|
|
593
|
+
* as `[...packages.client, ...packages.shared]` minus anything whose platform excludes the
|
|
594
|
+
* browser, and `mj codegen manifest --open-app-client-bootstrap` turns every enabled entry into an
|
|
595
|
+
* import in the shell's generated class-registrations manifest.
|
|
585
596
|
*
|
|
586
|
-
*
|
|
587
|
-
* on the premise that other roles "are imported normally"; the host
|
|
588
|
-
* is a required seven-value enum whose `components` / `module`
|
|
589
|
-
* roles. Anything narrower leaves a schema-valid package
|
|
590
|
-
* nobody — the
|
|
597
|
+
* There is deliberately no `role` FILTER here beyond the platform rule. An earlier revision kept
|
|
598
|
+
* only `role: 'bootstrap'` on the premise that other roles "are imported normally"; the host
|
|
599
|
+
* contradicts that, and `role` is a required seven-value enum whose `components` / `module`
|
|
600
|
+
* members are the documented Angular roles. Anything narrower leaves a schema-valid package
|
|
601
|
+
* imported by the shell and linked by nobody — the page-load-with-a-green-build failure this
|
|
602
|
+
* module exists to prevent (#4364).
|
|
603
|
+
*
|
|
604
|
+
* The platform rule itself IS a role test, but a targeted one: it drops only what cannot run in a
|
|
605
|
+
* browser at all. Before it existed, a Node-only actions package declared `shared` was imported
|
|
606
|
+
* into the Angular bundle and the host could not build (#4428).
|
|
591
607
|
*
|
|
592
608
|
* `packages.server[]` is NOT here, and that is not an oversight: the host routes it to
|
|
593
609
|
* `dynamicPackages.server`, a Node process that resolves importer-relative rather than from the
|
|
594
610
|
* vite root, so it is not part of the shell's resolution problem.
|
|
595
611
|
*/
|
|
596
612
|
function readShellImportedEntries(member) {
|
|
597
|
-
return [...readDeclaredEntries(member, 'client'), ...readDeclaredEntries(member, 'shared')];
|
|
613
|
+
return [...readDeclaredEntries(member, 'client'), ...readDeclaredEntries(member, 'shared')].filter(runsInBrowser);
|
|
614
|
+
}
|
|
615
|
+
/**
|
|
616
|
+
* Whether a declared package may be imported by the app shell.
|
|
617
|
+
*
|
|
618
|
+
* DELIBERATE COPY of `ResolvePackagePlatform` / `PackageRunsOnTier` in
|
|
619
|
+
* `packages/OpenApp/Engine/src/manifest/package-platform.ts`, which is canonical;
|
|
620
|
+
* `packages/DynamicPackages/src/discover.ts` keeps a third copy. Importing the engine's version
|
|
621
|
+
* here would bind this command to that package's built `dist/`. Change one, change all three. The
|
|
622
|
+
* engine's `package-platform.test.ts` holds the canonical case list; this module's spec mirrors its
|
|
623
|
+
* cases by hand, because it cannot import the engine.
|
|
624
|
+
*/
|
|
625
|
+
function runsInBrowser(pkg) {
|
|
626
|
+
// `readDeclaredEntries` has already rejected every `platform` other than absent or one of the
|
|
627
|
+
// three literals, so only `undefined` needs the role default here.
|
|
628
|
+
const platform = pkg.platform ?? (pkg.role === 'actions' ? 'node' : 'both');
|
|
629
|
+
return platform === 'both' || platform === 'browser';
|
|
598
630
|
}
|
|
599
631
|
export function CollectOpenAppClientPackages(members, workspacePackages) {
|
|
600
632
|
const collected = new Map();
|