@descix/cli 1.0.1 → 1.0.4
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.md +671 -0
- package/README.md +43 -4
- package/agent-assets/guides/README.md +2 -2
- package/agent-assets/guides/dynamic-site-pattern.md +29 -14
- package/agent-assets/guides/knowledge-only-pattern.md +5 -5
- package/agent-assets/guides/microservice-pattern.md +48 -4
- package/agent-assets/guides/static-site-pattern.md +8 -0
- package/agent-assets/instructions/app-asset-validation.md +5 -5
- package/agent-assets/instructions/onboarding-flow.md +4 -4
- package/agent-assets/instructions/standard-folder-structure.md +20 -11
- package/agent-assets/reference/app-creation.md +42 -20
- package/agent-assets/reference/architecture.md +24 -22
- package/agent-assets/reference/local-dev.md +230 -67
- package/agent-assets/reference/mcp-integration.md +21 -15
- package/agent-assets/reference/platform-api-consumer.md +244 -0
- package/agent-assets/reference/workspace-config.md +7 -7
- package/agent-assets/rules/descix_mcp.template.mdc +8 -8
- package/bin/descix.js +2559 -1435
- package/bin/kb-deny-lint.mjs +91 -0
- package/bin/mcp-server.js +175 -91
- package/lib/agent-files.js +37 -25
- package/lib/api-client.js +223 -56
- package/lib/auth-guard.js +13 -3
- package/lib/chat-session.js +187 -0
- package/lib/cli-version.js +59 -0
- package/lib/commands/airdrop.js +251 -0
- package/lib/commands/auth.js +254 -72
- package/lib/commands/briefer/errors.js +88 -0
- package/lib/commands/briefer/index.js +319 -0
- package/lib/commands/briefer/sources/canonical-sources.js +129 -0
- package/lib/commands/briefer/sources/entitlements.js +220 -0
- package/lib/commands/briefer/sources/environments.js +205 -0
- package/lib/commands/briefer/sources/identifiers.js +214 -0
- package/lib/commands/briefer/sources/microservice-deploy.js +267 -0
- package/lib/commands/briefer/sources/routing.js +275 -0
- package/lib/commands/briefer/sources/what-is-not.js +223 -0
- package/lib/commands/briefer/stitcher.js +134 -0
- package/lib/commands/briefer/util/source-reader.js +502 -0
- package/lib/commands/config.js +210 -90
- package/lib/commands/corpus.js +978 -0
- package/lib/commands/credits.js +122 -0
- package/lib/commands/health.js +627 -0
- package/lib/commands/kb-list-render.js +32 -0
- package/lib/commands/kb.js +190 -413
- package/lib/commands/mcp.js +5 -5
- package/lib/commands/microservice-restart.js +359 -0
- package/lib/commands/model-config.js +313 -0
- package/lib/commands/retired-kb-sync.js +134 -0
- package/lib/commands/serve.js +26 -1
- package/lib/commands/status.js +23 -51
- package/lib/commands/update.js +36 -107
- package/lib/core/Chunker.js +491 -17
- package/lib/core/CorpusDenyLint.js +326 -0
- package/lib/core/CorpusWalker.js +357 -0
- package/lib/core/Hydrator.js +75 -29
- package/lib/core/ManifestLoader.js +533 -0
- package/lib/core/SiteWalker.js +218 -0
- package/lib/core/Syncer.js +163 -11
- package/lib/diagnostic-log.js +41 -0
- package/lib/environment-report.js +100 -0
- package/lib/global-config.js +4 -1
- package/lib/oauth-client.js +164 -0
- package/lib/origin.js +143 -0
- package/lib/service-api-client.js +95 -0
- package/lib/wallet-environment.js +49 -0
- package/lib/wallet-file.js +16 -2
- package/lib/wizard/setup.js +10 -9
- package/lib/workspace-config.js +380 -235
- package/lib/workspace-identity.js +92 -0
- package/lib/workspace-utils.js +41 -61
- package/package.json +19 -6
- package/templates/agent-claude.md +157 -9
- package/templates/agent-cline.md +68 -8
- package/templates/agent-copilot.md +68 -8
- package/templates/agent-cursor.md +68 -8
- package/templates/alignment-schema.json +20 -0
- package/templates/cloud-brain-hook.sh +20 -0
- package/templates/drive/README.md +1 -1
- package/templates/drive_templates/README.md +2 -2
- package/templates/scaffolds/README.md +6 -10
- package/templates/scaffolds/microservice/SERVICE_README_sdk.md +104 -149
- package/templates/scaffolds/microservice/app.js +51 -10
- package/templates/scaffolds/microservice/app.yaml +2 -2
- package/templates/scaffolds/microservice/defaults-config-dev.json +4 -0
- package/templates/scaffolds/microservice/dev-overrides.example.json +5 -0
- package/templates/scaffolds/microservice/manifest.json +0 -1
- package/templates/scaffolds/microservice/package.json +3 -3
- package/templates/scaffolds/microservice/scripts/register.js +56 -41
- package/templates/scaffolds/microservice/services/mcpClient.js +55 -65
- package/templates/scaffolds/microservice/services/utils.js +20 -238
- package/templates/scaffolds/microservice/templates/SERVICE_README_TEMPLATE.md +24 -0
- package/lib/commands/app-wizard.js +0 -627
- package/lib/commands/folder.js +0 -291
- package/lib/core/PathContext.js +0 -335
- package/templates/scaffolds/microservice/dev-overrides.json.example +0 -5
- package/templates/scaffolds/site/DeSciXAppSDK.js +0 -62
- package/templates/scaffolds/site/README.md +0 -51
- package/templates/scaffolds/site/app.js +0 -22
- package/templates/scaffolds/site/index.html +0 -42
- package/templates/scaffolds/site/styles.css +0 -123
package/lib/commands/config.js
CHANGED
|
@@ -1,47 +1,48 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Configuration Commands
|
|
3
|
-
*
|
|
3
|
+
*
|
|
4
4
|
* Manage CLI configuration (.descix/workspace.json)
|
|
5
|
-
* Uses
|
|
5
|
+
* Uses WorkspaceConfig for path resolution - no process.cwd() lookups
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import chalk from 'chalk';
|
|
9
9
|
import * as path from 'path';
|
|
10
|
-
import { PathContext } from '../core/PathContext.js';
|
|
11
10
|
import { WorkspaceConfig } from '../workspace-config.js';
|
|
11
|
+
import { environmentNameFor } from '../environment-report.js';
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
14
|
* Show current configuration
|
|
15
15
|
*/
|
|
16
16
|
export async function show() {
|
|
17
17
|
try {
|
|
18
|
-
const
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
|
|
18
|
+
const workspaceConfig = await WorkspaceConfig.load();
|
|
19
|
+
const workspaceRoot = workspaceConfig.getWorkspaceRoot();
|
|
20
|
+
|
|
22
21
|
console.log(chalk.cyan('\n📋 DeSciX Workspace Configuration:\n'));
|
|
23
22
|
console.log(chalk.white(` Workspace: ${workspaceRoot}`));
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
23
|
+
// Under (A', contract rev 2) getApiUrl() ALWAYS yields an origin — a workspace that named
|
|
24
|
+
// none resolves to the declared default. The "(not configured)" branch is therefore
|
|
25
|
+
// unreachable and was DELETED, not fenced.
|
|
26
|
+
const configuredOrigin = workspaceConfig.getApiUrl();
|
|
27
|
+
console.log(chalk.white(` API URL: ${configuredOrigin}`));
|
|
28
|
+
// The environment NAME comes from the ONE owner that derives it from the origin. It used to
|
|
29
|
+
// read a separate `env.environment` key and fall back to the literal 'production' — a second
|
|
30
|
+
// derivation of the same fact, which could disagree with the origin printed one line above.
|
|
31
|
+
console.log(chalk.white(` Environment: ${environmentNameFor(configuredOrigin)}`));
|
|
32
|
+
|
|
33
|
+
// Show mapped apps (v2.1 env.products)
|
|
34
|
+
const platform = workspaceConfig.env?.platform;
|
|
35
|
+
const products = workspaceConfig.env?.products || [];
|
|
36
|
+
const allApps = [platform?.appId, ...products.map(p => p.appId)].filter(Boolean);
|
|
37
|
+
if (allApps.length > 0) {
|
|
38
|
+
console.log(chalk.white(` Apps: ${allApps.join(', ')}`));
|
|
38
39
|
}
|
|
39
|
-
|
|
40
|
+
|
|
40
41
|
console.log('');
|
|
41
42
|
const configPath = path.join(workspaceRoot, '.descix', 'workspace.json');
|
|
42
43
|
console.log(chalk.gray(` Config file: ${configPath}`));
|
|
43
44
|
console.log('');
|
|
44
|
-
|
|
45
|
+
|
|
45
46
|
} catch (error) {
|
|
46
47
|
console.error(chalk.red('Error loading config:', error.message));
|
|
47
48
|
throw error;
|
|
@@ -53,18 +54,17 @@ export async function show() {
|
|
|
53
54
|
*/
|
|
54
55
|
export async function setUrl(url, options = {}) {
|
|
55
56
|
try {
|
|
56
|
-
const
|
|
57
|
-
const workspaceRoot =
|
|
58
|
-
|
|
59
|
-
const workspaceConfig = await WorkspaceConfig.load(workspaceRoot);
|
|
57
|
+
const workspaceConfig = await WorkspaceConfig.load();
|
|
58
|
+
const workspaceRoot = workspaceConfig.getWorkspaceRoot();
|
|
59
|
+
|
|
60
60
|
workspaceConfig.apiUrl = url;
|
|
61
61
|
workspaceConfig.environment = url.includes('localhost') ? 'development' : 'production';
|
|
62
62
|
const configPath = await workspaceConfig.save(workspaceRoot);
|
|
63
|
-
|
|
63
|
+
|
|
64
64
|
console.log(chalk.green('\n✅ Configuration updated!\n'));
|
|
65
65
|
console.log(chalk.white(` API URL: ${url}`));
|
|
66
66
|
console.log(chalk.gray(` Saved to: ${configPath}\n`));
|
|
67
|
-
|
|
67
|
+
|
|
68
68
|
} catch (error) {
|
|
69
69
|
console.error(chalk.red('Error updating config:', error.message));
|
|
70
70
|
throw error;
|
|
@@ -74,29 +74,41 @@ export async function setUrl(url, options = {}) {
|
|
|
74
74
|
/**
|
|
75
75
|
* Initialize config for environment
|
|
76
76
|
*/
|
|
77
|
-
export async function init(env
|
|
77
|
+
export async function init(env, options = {}) {
|
|
78
78
|
try {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
} else {
|
|
89
|
-
workspaceConfig.apiUrl = 'https://descix.net';
|
|
90
|
-
workspaceConfig.environment = 'production';
|
|
79
|
+
// NO DEFAULT ENVIRONMENT. This used to be `init(env = 'prod')` with an `if (env === 'dev')
|
|
80
|
+
// … else <production>` body, which meant a bare `descix config init` — and ANY unrecognised
|
|
81
|
+
// environment name, including a typo — silently wrote the PRODUCTION origin into the
|
|
82
|
+
// workspace. That is precisely "an origin the developer did not choose".
|
|
83
|
+
if (!env) {
|
|
84
|
+
throw new Error(
|
|
85
|
+
'descix config init requires an environment: --env dev|demo|prod.\n' +
|
|
86
|
+
'There is no default — the origin this workspace talks to is a choice, not an omission.'
|
|
87
|
+
);
|
|
91
88
|
}
|
|
92
|
-
|
|
93
|
-
const
|
|
94
|
-
|
|
89
|
+
|
|
90
|
+
const normalized = String(env).toLowerCase();
|
|
91
|
+
const known = WorkspaceConfig.ENV_MAP[normalized];
|
|
92
|
+
if (!known) {
|
|
93
|
+
throw new Error(
|
|
94
|
+
`Unknown environment "${env}". Known environments: ` +
|
|
95
|
+
`${Object.keys(WorkspaceConfig.ENV_MAP).join(', ')}.\n` +
|
|
96
|
+
'For a self-hosted or port-forwarded gateway use ' +
|
|
97
|
+
'`descix config set-env <name> --url https://...`.'
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Write through the CANONICAL writer. This function used to assign the LEGACY top-level
|
|
102
|
+
// `workspaceConfig.apiUrl`, while `config set-env` writes `env.apiUrl` — two writers of one
|
|
103
|
+
// fact, writing two different keys, one of which `getApiUrl()` only consults as a fallback.
|
|
104
|
+
const workspaceConfig = await WorkspaceConfig.load();
|
|
105
|
+
const result = await workspaceConfig.setEnvironment(normalized, options.url || null);
|
|
106
|
+
|
|
95
107
|
console.log(chalk.green('\n✅ Configuration initialized!\n'));
|
|
96
|
-
console.log(chalk.white(` Environment: ${
|
|
97
|
-
console.log(chalk.white(` API URL: ${
|
|
98
|
-
console.log(chalk.gray(` Saved to: ${configPath}\n`));
|
|
99
|
-
|
|
108
|
+
console.log(chalk.white(` Environment: ${result.environment}`));
|
|
109
|
+
console.log(chalk.white(` API URL: ${result.apiUrl}`));
|
|
110
|
+
console.log(chalk.gray(` Saved to: ${result.configPath}\n`));
|
|
111
|
+
|
|
100
112
|
} catch (error) {
|
|
101
113
|
console.error(chalk.red('Error initializing config:', error.message));
|
|
102
114
|
throw error;
|
|
@@ -104,52 +116,160 @@ export async function init(env = 'prod', options = {}) {
|
|
|
104
116
|
}
|
|
105
117
|
|
|
106
118
|
/**
|
|
107
|
-
* Set
|
|
108
|
-
*
|
|
109
|
-
*
|
|
119
|
+
* Set target environment persistently in workspace.json.
|
|
120
|
+
* After switching, auto-runs reconnect against the new API URL.
|
|
121
|
+
*
|
|
122
|
+
* @param {string} envName - Environment: dev, demo, prod, or custom name
|
|
123
|
+
* @param {Object} options - { url?: string } optional URL override for custom envs
|
|
110
124
|
*/
|
|
111
|
-
export async function
|
|
125
|
+
export async function setEnv(envName, options = {}) {
|
|
112
126
|
try {
|
|
113
|
-
const
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
//
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
throw new Error(`App "${appId}" not found in community "${communityId}"`);
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
workspaceConfig.communities[communityId].apps[appId].sync_mode = mode;
|
|
135
|
-
|
|
136
|
-
const configPath = await workspaceConfig.save(workspaceRoot);
|
|
137
|
-
|
|
138
|
-
console.log(chalk.green('\n✅ Sync mode updated!\n'));
|
|
139
|
-
console.log(chalk.white(` Community: ${communityId}`));
|
|
140
|
-
console.log(chalk.white(` App: ${appId}`));
|
|
141
|
-
console.log(chalk.white(` Sync Mode: ${mode}`));
|
|
142
|
-
console.log(chalk.gray(` Saved to: ${configPath}\n`));
|
|
143
|
-
|
|
144
|
-
if (mode === 'git') {
|
|
145
|
-
console.log(chalk.cyan(' Tip: Use "descix kb build" to process KB locally.'));
|
|
127
|
+
const workspaceConfig = await WorkspaceConfig.load();
|
|
128
|
+
|
|
129
|
+
const result = await workspaceConfig.setEnvironment(envName, options.url || null);
|
|
130
|
+
|
|
131
|
+
console.log(chalk.green('\n✅ Environment switched!\n'));
|
|
132
|
+
console.log(chalk.white(` Environment: ${result.environment}`));
|
|
133
|
+
// The `|| https://localhost:<microservice.port>` branch that stood here DERIVED AN ORIGIN
|
|
134
|
+
// FROM A PLATFORM PORT and printed it as the API URL — the exact construction CEO-D
|
|
135
|
+
// 2026-08-18 forbids ("an environment NAME never derives localhost from a platform port")
|
|
136
|
+
// and a misreport of an origin the developer never chose. setEnvironment() always returns a
|
|
137
|
+
// real apiUrl, so the branch was unreachable as well as wrong. DELETED.
|
|
138
|
+
console.log(chalk.white(` API URL: ${result.apiUrl}`));
|
|
139
|
+
console.log(chalk.white(` Secret Label: ${result.secretLabel}`));
|
|
140
|
+
console.log(chalk.gray(` Saved to: ${result.configPath}\n`));
|
|
141
|
+
|
|
142
|
+
// Auto-reconnect against the new environment
|
|
143
|
+
if (result.apiUrl) {
|
|
144
|
+
process.env.DESCIX_API_URL = result.apiUrl;
|
|
146
145
|
} else {
|
|
147
|
-
|
|
146
|
+
delete process.env.DESCIX_API_URL;
|
|
148
147
|
}
|
|
149
|
-
|
|
150
|
-
|
|
148
|
+
|
|
149
|
+
console.log(chalk.cyan(' Reconnecting to new environment...\n'));
|
|
150
|
+
try {
|
|
151
|
+
const { reconnect } = await import('./auth.js');
|
|
152
|
+
await reconnect();
|
|
153
|
+
} catch (err) {
|
|
154
|
+
console.log(chalk.yellow(`\n ⚠️ Auto-reconnect failed: ${err.message}`));
|
|
155
|
+
console.log(chalk.gray(' Run "descix reconnect" or "descix login" manually.\n'));
|
|
156
|
+
}
|
|
157
|
+
|
|
151
158
|
} catch (error) {
|
|
152
|
-
console.error(chalk.red(
|
|
159
|
+
console.error(chalk.red(`\n❌ ${error.message}\n`));
|
|
153
160
|
throw error;
|
|
154
161
|
}
|
|
155
162
|
}
|
|
163
|
+
|
|
164
|
+
// ─── Workspace-level env keys (redteam G-6) ──────────────────────────────────
|
|
165
|
+
// env.gateway.port, env.devCerts, env.powchUrl and env.siteUrl are read by the
|
|
166
|
+
// gateway and the shell build, but had NO verb — the only way to set them was to
|
|
167
|
+
// hand-edit .descix/workspace.json. The target UX is that a developer never
|
|
168
|
+
// hand-crafts that file, so each of these now has a command.
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Shared writer: set one key, report it, and say where it landed.
|
|
172
|
+
*
|
|
173
|
+
* `produceValue` is a THUNK, not a value, so validation runs INSIDE this
|
|
174
|
+
* try/catch. Passing an already-validated value meant a rejection threw at the
|
|
175
|
+
* call site, propagated to the CLI action's `catch { process.exit(1) }`, and the
|
|
176
|
+
* developer got a bare exit code with no message — a fail-loud that fails
|
|
177
|
+
* silently, which is worse than no validation because it looks like a crash.
|
|
178
|
+
*/
|
|
179
|
+
async function setWorkspaceEnvKey(dottedKey, produceValue, label) {
|
|
180
|
+
try {
|
|
181
|
+
const value = typeof produceValue === 'function' ? produceValue() : produceValue;
|
|
182
|
+
const workspaceConfig = await WorkspaceConfig.load();
|
|
183
|
+
const configPath = await workspaceConfig.setEnvKey(dottedKey, value);
|
|
184
|
+
console.log(chalk.green(`\n✅ ${label}\n`));
|
|
185
|
+
console.log(chalk.white(` env.${dottedKey}: ${value === null ? chalk.gray('(removed)') : value}`));
|
|
186
|
+
console.log(chalk.gray(` Saved to: ${configPath}\n`));
|
|
187
|
+
return configPath;
|
|
188
|
+
} catch (error) {
|
|
189
|
+
console.error(chalk.red(`\n❌ ${error.message}\n`));
|
|
190
|
+
throw error;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/** Reject anything that is not a usable port BEFORE it reaches the file. */
|
|
195
|
+
function assertPort(value) {
|
|
196
|
+
const port = Number(value);
|
|
197
|
+
if (!Number.isInteger(port) || port < 1 || port > 65535) {
|
|
198
|
+
throw new Error(`Port must be an integer 1-65535, got "${value}".`);
|
|
199
|
+
}
|
|
200
|
+
return port;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/** Reject anything that is not an absolute http(s) URL BEFORE it reaches the file. */
|
|
204
|
+
function assertUrl(value, what) {
|
|
205
|
+
let parsed;
|
|
206
|
+
try {
|
|
207
|
+
parsed = new URL(value);
|
|
208
|
+
} catch {
|
|
209
|
+
throw new Error(`${what} must be an absolute URL (e.g. https://powch.dev.descix.net), got "${value}".`);
|
|
210
|
+
}
|
|
211
|
+
if (parsed.protocol !== 'https:' && parsed.protocol !== 'http:') {
|
|
212
|
+
throw new Error(`${what} must be http(s), got "${parsed.protocol}//".`);
|
|
213
|
+
}
|
|
214
|
+
return value;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Set the port `descix serve` listens on (env.gateway.port).
|
|
219
|
+
*/
|
|
220
|
+
export async function setGatewayPort(port) {
|
|
221
|
+
return setWorkspaceEnvKey(
|
|
222
|
+
'gateway.port',
|
|
223
|
+
() => (port === null ? null : assertPort(port)),
|
|
224
|
+
'Gateway port set — `descix serve` will listen here and the shell product map will match it.',
|
|
225
|
+
);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Point the local dev servers at a specific TLS cert pair (env.devCerts.*).
|
|
230
|
+
* One owner: the gateway AND every app dev server behind it read this.
|
|
231
|
+
*/
|
|
232
|
+
export async function setDevCerts(options = {}) {
|
|
233
|
+
const { dir, cert, key, clear } = options;
|
|
234
|
+
if (clear) {
|
|
235
|
+
await setWorkspaceEnvKey('devCerts.dir', null, 'Dev certs cleared — falling back to the SDK-tracked SAN pair.');
|
|
236
|
+
await setWorkspaceEnvKey('devCerts.cert', null, 'Dev cert file cleared.');
|
|
237
|
+
return setWorkspaceEnvKey('devCerts.key', null, 'Dev key file cleared.');
|
|
238
|
+
}
|
|
239
|
+
if (!dir && !cert && !key) {
|
|
240
|
+
const message =
|
|
241
|
+
'Nothing to set. Pass --dir <path> (a directory holding cert.pem + key.pem), ' +
|
|
242
|
+
'or --cert <path> and --key <path>, or --clear to remove.';
|
|
243
|
+
console.error(chalk.red(`\n❌ ${message}\n`));
|
|
244
|
+
throw new Error(message);
|
|
245
|
+
}
|
|
246
|
+
let last;
|
|
247
|
+
if (dir) last = await setWorkspaceEnvKey('devCerts.dir', path.resolve(dir), 'Dev cert directory set.');
|
|
248
|
+
if (cert) last = await setWorkspaceEnvKey('devCerts.cert', path.resolve(cert), 'Dev certificate set.');
|
|
249
|
+
if (key) last = await setWorkspaceEnvKey('devCerts.key', path.resolve(key), 'Dev private key set.');
|
|
250
|
+
return last;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* Set where Powch lives (env.powchUrl).
|
|
255
|
+
* Powch is CROSS-ORIGIN from the shell by design — it holds passkeys and the
|
|
256
|
+
* wallet — so this is its own origin, never a path on the gateway.
|
|
257
|
+
*/
|
|
258
|
+
export async function setPowchUrl(url) {
|
|
259
|
+
return setWorkspaceEnvKey(
|
|
260
|
+
'powchUrl',
|
|
261
|
+
() => (url === null ? null : assertUrl(url, 'Powch URL')),
|
|
262
|
+
'Powch URL set — the gateway and the shell build now agree on it.',
|
|
263
|
+
);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* Set the App Shell origin `descix serve` proxies `/` to (env.siteUrl).
|
|
268
|
+
*/
|
|
269
|
+
export async function setSiteUrl(url) {
|
|
270
|
+
return setWorkspaceEnvKey(
|
|
271
|
+
'siteUrl',
|
|
272
|
+
() => (url === null ? null : assertUrl(url, 'Site URL')),
|
|
273
|
+
'App Shell URL set — `descix serve` will proxy / here.',
|
|
274
|
+
);
|
|
275
|
+
}
|