@dashai/cli 0.3.2 → 0.5.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/dist/bin.js +707 -44
- package/dist/bin.js.map +1 -1
- package/package.json +1 -1
package/dist/bin.js
CHANGED
|
@@ -231,6 +231,30 @@ async function destroyDevInstallation(installationId, options = {}) {
|
|
|
231
231
|
options
|
|
232
232
|
);
|
|
233
233
|
}
|
|
234
|
+
async function createApiKey(installationId, body, options = {}) {
|
|
235
|
+
return apiRequest(
|
|
236
|
+
"POST",
|
|
237
|
+
`/api/installations/${installationId}/api-keys`,
|
|
238
|
+
body,
|
|
239
|
+
options
|
|
240
|
+
);
|
|
241
|
+
}
|
|
242
|
+
async function listApiKeys(installationId, options = {}) {
|
|
243
|
+
return apiRequest(
|
|
244
|
+
"GET",
|
|
245
|
+
`/api/installations/${installationId}/api-keys`,
|
|
246
|
+
void 0,
|
|
247
|
+
options
|
|
248
|
+
);
|
|
249
|
+
}
|
|
250
|
+
async function revokeApiKey(installationId, keyId, options = {}) {
|
|
251
|
+
return apiRequest(
|
|
252
|
+
"DELETE",
|
|
253
|
+
`/api/installations/${installationId}/api-keys/${keyId}`,
|
|
254
|
+
void 0,
|
|
255
|
+
options
|
|
256
|
+
);
|
|
257
|
+
}
|
|
234
258
|
async function createTable(installationId, body, options = {}) {
|
|
235
259
|
return apiRequest(
|
|
236
260
|
"POST",
|
|
@@ -2032,6 +2056,47 @@ var init_init = __esm({
|
|
|
2032
2056
|
init_workspaces();
|
|
2033
2057
|
}
|
|
2034
2058
|
});
|
|
2059
|
+
function loadSchemaCommandContext(opts) {
|
|
2060
|
+
const projectRoot = resolve(opts.dir ?? process.cwd());
|
|
2061
|
+
const manifestPath2 = join(projectRoot, "module.json");
|
|
2062
|
+
const manifest = readManifestOrThrow(projectRoot);
|
|
2063
|
+
const manifestRawBytes = readFileSync(manifestPath2, "utf-8");
|
|
2064
|
+
const slug = manifest.module?.slug;
|
|
2065
|
+
if (!slug) {
|
|
2066
|
+
throw new Error(
|
|
2067
|
+
`module.json at ${manifestPath2} has no module.slug \u2014 the manifest is malformed.`
|
|
2068
|
+
);
|
|
2069
|
+
}
|
|
2070
|
+
const cfg = readConfig();
|
|
2071
|
+
if (!cfg) {
|
|
2072
|
+
throw new Error("Not logged in. Run `dashwise login` first.");
|
|
2073
|
+
}
|
|
2074
|
+
const entry = readModuleEntry(slug);
|
|
2075
|
+
if (!entry) {
|
|
2076
|
+
throw new Error(
|
|
2077
|
+
`No dev install cached for module "${slug}". Run \`dashwise init ${slug} --force\` to provision one.`
|
|
2078
|
+
);
|
|
2079
|
+
}
|
|
2080
|
+
return {
|
|
2081
|
+
projectRoot,
|
|
2082
|
+
manifestPath: manifestPath2,
|
|
2083
|
+
manifest,
|
|
2084
|
+
manifestRawBytes,
|
|
2085
|
+
slug,
|
|
2086
|
+
cfg,
|
|
2087
|
+
entry,
|
|
2088
|
+
requestOptions: {
|
|
2089
|
+
baseUrl: resolveApiUrl(),
|
|
2090
|
+
auth: { token: entry.runtimeToken }
|
|
2091
|
+
}
|
|
2092
|
+
};
|
|
2093
|
+
}
|
|
2094
|
+
var init_schema_command_context = __esm({
|
|
2095
|
+
"src/lib/schema-command-context.ts"() {
|
|
2096
|
+
init_config();
|
|
2097
|
+
init_manifest_io();
|
|
2098
|
+
}
|
|
2099
|
+
});
|
|
2035
2100
|
|
|
2036
2101
|
// src/commands/module/destroy-dev-install.ts
|
|
2037
2102
|
var destroy_dev_install_exports = {};
|
|
@@ -2202,47 +2267,6 @@ var init_reset_dev_install = __esm({
|
|
|
2202
2267
|
init_output();
|
|
2203
2268
|
}
|
|
2204
2269
|
});
|
|
2205
|
-
function loadSchemaCommandContext(opts) {
|
|
2206
|
-
const projectRoot = resolve(opts.dir ?? process.cwd());
|
|
2207
|
-
const manifestPath2 = join(projectRoot, "module.json");
|
|
2208
|
-
const manifest = readManifestOrThrow(projectRoot);
|
|
2209
|
-
const manifestRawBytes = readFileSync(manifestPath2, "utf-8");
|
|
2210
|
-
const slug = manifest.module?.slug;
|
|
2211
|
-
if (!slug) {
|
|
2212
|
-
throw new Error(
|
|
2213
|
-
`module.json at ${manifestPath2} has no module.slug \u2014 the manifest is malformed.`
|
|
2214
|
-
);
|
|
2215
|
-
}
|
|
2216
|
-
const cfg = readConfig();
|
|
2217
|
-
if (!cfg) {
|
|
2218
|
-
throw new Error("Not logged in. Run `dashwise login` first.");
|
|
2219
|
-
}
|
|
2220
|
-
const entry = readModuleEntry(slug);
|
|
2221
|
-
if (!entry) {
|
|
2222
|
-
throw new Error(
|
|
2223
|
-
`No dev install cached for module "${slug}". Run \`dashwise init ${slug} --force\` to provision one.`
|
|
2224
|
-
);
|
|
2225
|
-
}
|
|
2226
|
-
return {
|
|
2227
|
-
projectRoot,
|
|
2228
|
-
manifestPath: manifestPath2,
|
|
2229
|
-
manifest,
|
|
2230
|
-
manifestRawBytes,
|
|
2231
|
-
slug,
|
|
2232
|
-
cfg,
|
|
2233
|
-
entry,
|
|
2234
|
-
requestOptions: {
|
|
2235
|
-
baseUrl: resolveApiUrl(),
|
|
2236
|
-
auth: { token: entry.runtimeToken }
|
|
2237
|
-
}
|
|
2238
|
-
};
|
|
2239
|
-
}
|
|
2240
|
-
var init_schema_command_context = __esm({
|
|
2241
|
-
"src/lib/schema-command-context.ts"() {
|
|
2242
|
-
init_config();
|
|
2243
|
-
init_manifest_io();
|
|
2244
|
-
}
|
|
2245
|
-
});
|
|
2246
2270
|
|
|
2247
2271
|
// src/lib/field-spec.ts
|
|
2248
2272
|
function parseFieldSpec(spec) {
|
|
@@ -2707,10 +2731,76 @@ var init_set_type = __esm({
|
|
|
2707
2731
|
init_api_client();
|
|
2708
2732
|
init_config();
|
|
2709
2733
|
init_manifest_io();
|
|
2734
|
+
|
|
2735
|
+
// src/lib/manifest-poll.ts
|
|
2736
|
+
init_api_client();
|
|
2737
|
+
function startManifestPollLoop(opts) {
|
|
2738
|
+
const {
|
|
2739
|
+
installationId,
|
|
2740
|
+
manifestPath: manifestPath2,
|
|
2741
|
+
requestOptions,
|
|
2742
|
+
intervalMs,
|
|
2743
|
+
onUpdate,
|
|
2744
|
+
onError
|
|
2745
|
+
} = opts;
|
|
2746
|
+
let lastSeenJson = existsSync(manifestPath2) ? readFileSync(manifestPath2, "utf-8") : "";
|
|
2747
|
+
let timer = null;
|
|
2748
|
+
let stopped = false;
|
|
2749
|
+
const tick = async () => {
|
|
2750
|
+
if (stopped) return;
|
|
2751
|
+
try {
|
|
2752
|
+
const { manifest } = await getInstallationSchema(
|
|
2753
|
+
installationId,
|
|
2754
|
+
requestOptions
|
|
2755
|
+
);
|
|
2756
|
+
const remoteJson = JSON.stringify(manifest, null, 2) + "\n";
|
|
2757
|
+
const currentLocal = existsSync(manifestPath2) ? readFileSync(manifestPath2, "utf-8") : "";
|
|
2758
|
+
if (remoteJson === currentLocal) {
|
|
2759
|
+
lastSeenJson = remoteJson;
|
|
2760
|
+
} else if (remoteJson !== lastSeenJson) {
|
|
2761
|
+
writeFileSync(manifestPath2, remoteJson, "utf-8");
|
|
2762
|
+
lastSeenJson = remoteJson;
|
|
2763
|
+
if (onUpdate) {
|
|
2764
|
+
const delta = Buffer.byteLength(remoteJson, "utf8") - Buffer.byteLength(currentLocal, "utf8");
|
|
2765
|
+
const deltaStr = delta === 0 ? "0 bytes" : `${delta > 0 ? "+" : ""}${delta} bytes`;
|
|
2766
|
+
onUpdate(
|
|
2767
|
+
`Backend manifest changed \u2014 synced to module.json (${deltaStr}).`
|
|
2768
|
+
);
|
|
2769
|
+
}
|
|
2770
|
+
}
|
|
2771
|
+
} catch (err) {
|
|
2772
|
+
if (onError) {
|
|
2773
|
+
const message = err instanceof ApiError ? `${err.code} (HTTP ${err.status}): ${err.message}` : err.message;
|
|
2774
|
+
onError(new Error(message));
|
|
2775
|
+
}
|
|
2776
|
+
} finally {
|
|
2777
|
+
if (!stopped) {
|
|
2778
|
+
timer = setTimeout(() => void tick(), intervalMs);
|
|
2779
|
+
}
|
|
2780
|
+
}
|
|
2781
|
+
};
|
|
2782
|
+
timer = setTimeout(() => void tick(), intervalMs);
|
|
2783
|
+
return {
|
|
2784
|
+
stop: () => {
|
|
2785
|
+
if (stopped) return;
|
|
2786
|
+
stopped = true;
|
|
2787
|
+
if (timer) {
|
|
2788
|
+
clearTimeout(timer);
|
|
2789
|
+
timer = null;
|
|
2790
|
+
}
|
|
2791
|
+
},
|
|
2792
|
+
isRunning: () => !stopped
|
|
2793
|
+
};
|
|
2794
|
+
}
|
|
2795
|
+
|
|
2796
|
+
// src/commands/dev.ts
|
|
2710
2797
|
init_output();
|
|
2711
2798
|
var DEFAULT_NEXT_PORT = 3e3;
|
|
2712
2799
|
var PREFIX_SDK = `\x1B[36m[sdk]\x1B[0m `;
|
|
2713
2800
|
var PREFIX_NEXT = `\x1B[35m[next]\x1B[0m `;
|
|
2801
|
+
var PREFIX_POLL = `\x1B[33m[poll]\x1B[0m `;
|
|
2802
|
+
var DEFAULT_REMOTE_POLL_INTERVAL_SEC = 5;
|
|
2803
|
+
var MIN_REMOTE_POLL_INTERVAL_SEC = 1;
|
|
2714
2804
|
async function devCommand(options) {
|
|
2715
2805
|
if (options.sdkOnly && options.nextOnly) {
|
|
2716
2806
|
fail(
|
|
@@ -2845,10 +2935,43 @@ async function devCommand(options) {
|
|
|
2845
2935
|
pipeWithPrefix(child.stdout, process.stdout, prefix);
|
|
2846
2936
|
pipeWithPrefix(child.stderr, process.stderr, prefix);
|
|
2847
2937
|
}
|
|
2938
|
+
let manifestPoll = null;
|
|
2939
|
+
const enablePoll = !options.noRemotePoll && moduleEntry !== null && manifestSlug !== void 0;
|
|
2940
|
+
if (enablePoll) {
|
|
2941
|
+
const intervalSec = Math.max(
|
|
2942
|
+
MIN_REMOTE_POLL_INTERVAL_SEC,
|
|
2943
|
+
options.remotePollIntervalSec ?? DEFAULT_REMOTE_POLL_INTERVAL_SEC
|
|
2944
|
+
);
|
|
2945
|
+
manifestPoll = startManifestPollLoop({
|
|
2946
|
+
installationId: moduleEntry.installationId,
|
|
2947
|
+
manifestPath: manifestPath2,
|
|
2948
|
+
requestOptions: {
|
|
2949
|
+
baseUrl: apiUrl,
|
|
2950
|
+
auth: { token: moduleEntry.runtimeToken }
|
|
2951
|
+
},
|
|
2952
|
+
intervalMs: intervalSec * 1e3,
|
|
2953
|
+
onUpdate: (msg) => {
|
|
2954
|
+
process.stdout.write(`${PREFIX_POLL}${msg}
|
|
2955
|
+
`);
|
|
2956
|
+
},
|
|
2957
|
+
onError: (err) => {
|
|
2958
|
+
process.stderr.write(`${PREFIX_POLL}${err.message}
|
|
2959
|
+
`);
|
|
2960
|
+
}
|
|
2961
|
+
});
|
|
2962
|
+
info(
|
|
2963
|
+
` ${dim("poll")} backend manifest every ${intervalSec}s ${dim("(--no-remote-poll to disable)")}`
|
|
2964
|
+
);
|
|
2965
|
+
info("");
|
|
2966
|
+
}
|
|
2848
2967
|
let shuttingDown = false;
|
|
2849
2968
|
const forwardSignal = (sig) => {
|
|
2850
2969
|
if (shuttingDown) return;
|
|
2851
2970
|
shuttingDown = true;
|
|
2971
|
+
if (manifestPoll) {
|
|
2972
|
+
manifestPoll.stop();
|
|
2973
|
+
manifestPoll = null;
|
|
2974
|
+
}
|
|
2852
2975
|
info(`
|
|
2853
2976
|
Received ${sig}, stopping children\u2026`);
|
|
2854
2977
|
for (const { child } of children) {
|
|
@@ -2885,6 +3008,10 @@ Received ${sig}, stopping children\u2026`);
|
|
|
2885
3008
|
}
|
|
2886
3009
|
}
|
|
2887
3010
|
}
|
|
3011
|
+
if (manifestPoll) {
|
|
3012
|
+
manifestPoll.stop();
|
|
3013
|
+
manifestPoll = null;
|
|
3014
|
+
}
|
|
2888
3015
|
const exitCode = Math.max(0, ...results.map((r) => r.code));
|
|
2889
3016
|
if (exitCode === 0) {
|
|
2890
3017
|
success("Dev loop stopped cleanly.");
|
|
@@ -5030,6 +5157,457 @@ async function depsRemoveCommand(providerSlug, options) {
|
|
|
5030
5157
|
return 0;
|
|
5031
5158
|
}
|
|
5032
5159
|
|
|
5160
|
+
// src/commands/pull.ts
|
|
5161
|
+
init_api_client();
|
|
5162
|
+
init_manifest_io();
|
|
5163
|
+
init_schema_command_context();
|
|
5164
|
+
init_output();
|
|
5165
|
+
async function pullCommand(options) {
|
|
5166
|
+
let ctx;
|
|
5167
|
+
try {
|
|
5168
|
+
ctx = loadSchemaCommandContext({
|
|
5169
|
+
...options.dir !== void 0 ? { dir: options.dir } : {}
|
|
5170
|
+
});
|
|
5171
|
+
} catch (err) {
|
|
5172
|
+
fail(err.message);
|
|
5173
|
+
return 1;
|
|
5174
|
+
}
|
|
5175
|
+
info(`Pulling manifest for installation ${ctx.entry.installationId}\u2026`);
|
|
5176
|
+
let remoteManifest;
|
|
5177
|
+
try {
|
|
5178
|
+
const response = await getInstallationSchema(
|
|
5179
|
+
ctx.entry.installationId,
|
|
5180
|
+
ctx.requestOptions
|
|
5181
|
+
);
|
|
5182
|
+
remoteManifest = response.manifest;
|
|
5183
|
+
} catch (err) {
|
|
5184
|
+
return surfacePullFailure(err);
|
|
5185
|
+
}
|
|
5186
|
+
const localJson = JSON.stringify(ctx.manifest, null, 2) + "\n";
|
|
5187
|
+
const remoteJson = JSON.stringify(remoteManifest, null, 2) + "\n";
|
|
5188
|
+
if (localJson === remoteJson) {
|
|
5189
|
+
success("Already in sync \u2014 local module.json matches backend.");
|
|
5190
|
+
return 0;
|
|
5191
|
+
}
|
|
5192
|
+
const localBytes = Buffer.byteLength(localJson, "utf8");
|
|
5193
|
+
const remoteBytes = Buffer.byteLength(remoteJson, "utf8");
|
|
5194
|
+
const delta = remoteBytes - localBytes;
|
|
5195
|
+
const deltaStr = delta === 0 ? "0 bytes" : `${delta > 0 ? "+" : ""}${delta} bytes`;
|
|
5196
|
+
if (options.dryRun) {
|
|
5197
|
+
info(
|
|
5198
|
+
`Drift detected (${deltaStr}). ${code("--dry-run")} \u2014 not writing.`
|
|
5199
|
+
);
|
|
5200
|
+
info(`Run ${code("dashwise pull")} without ${code("--dry-run")} to apply.`);
|
|
5201
|
+
return 0;
|
|
5202
|
+
}
|
|
5203
|
+
try {
|
|
5204
|
+
writeManifest(remoteManifest, ctx.projectRoot);
|
|
5205
|
+
} catch (err) {
|
|
5206
|
+
fail(`Failed to write ${manifestPath(ctx.projectRoot)}: ${err.message}`);
|
|
5207
|
+
return 1;
|
|
5208
|
+
}
|
|
5209
|
+
success(
|
|
5210
|
+
`Synced module.json from backend (${deltaStr}). ${dim(`Run \`dashwise module generate\` to refresh typed SDK if your watcher isn't running.`)}`
|
|
5211
|
+
);
|
|
5212
|
+
return 0;
|
|
5213
|
+
}
|
|
5214
|
+
function surfacePullFailure(err) {
|
|
5215
|
+
if (err instanceof ApiError) {
|
|
5216
|
+
switch (err.code) {
|
|
5217
|
+
case "UNAUTHENTICATED":
|
|
5218
|
+
fail(
|
|
5219
|
+
`Runtime token rejected. The cached token for this module may be expired \u2014 re-run \`dashwise init <slug> --force\` to mint a fresh one.`
|
|
5220
|
+
);
|
|
5221
|
+
break;
|
|
5222
|
+
case "SANDBOX_TOKEN_NOT_ACCEPTED":
|
|
5223
|
+
fail(
|
|
5224
|
+
`Schema-read endpoint requires a local-dev runtime token (kind=local). The cached token is the wrong kind \u2014 re-run \`dashwise init <slug> --force\`.`
|
|
5225
|
+
);
|
|
5226
|
+
break;
|
|
5227
|
+
case "INSTALL_MISMATCH":
|
|
5228
|
+
fail(
|
|
5229
|
+
`Runtime token is bound to a different installation than expected. The cached install id may be stale \u2014 re-run \`dashwise init <slug> --force\`.`
|
|
5230
|
+
);
|
|
5231
|
+
break;
|
|
5232
|
+
case "INSTALLATION_NOT_FOUND":
|
|
5233
|
+
fail(
|
|
5234
|
+
`The backend has no record of this installation. It may have been destroyed (GC, manual cleanup). Re-run \`dashwise init <slug>\` to provision a fresh one.`
|
|
5235
|
+
);
|
|
5236
|
+
break;
|
|
5237
|
+
default:
|
|
5238
|
+
fail(`Backend rejected: ${err.code} ${err.status} \u2014 ${err.message}`);
|
|
5239
|
+
}
|
|
5240
|
+
return 1;
|
|
5241
|
+
}
|
|
5242
|
+
fail(`Pull failed: ${err.message}`);
|
|
5243
|
+
return 1;
|
|
5244
|
+
}
|
|
5245
|
+
|
|
5246
|
+
// src/commands/api-keys.ts
|
|
5247
|
+
init_api_client();
|
|
5248
|
+
init_config();
|
|
5249
|
+
init_manifest_io();
|
|
5250
|
+
init_output();
|
|
5251
|
+
function loadContext(opts) {
|
|
5252
|
+
const manifest = readManifestOrThrow(opts.dir);
|
|
5253
|
+
const slug = manifest.module?.slug;
|
|
5254
|
+
if (!slug) {
|
|
5255
|
+
throw new Error(
|
|
5256
|
+
`module.json has no module.slug \u2014 the manifest is malformed.`
|
|
5257
|
+
);
|
|
5258
|
+
}
|
|
5259
|
+
const cfg = readConfig();
|
|
5260
|
+
if (!cfg) {
|
|
5261
|
+
throw new Error("Not logged in. Run `dashwise login` first.");
|
|
5262
|
+
}
|
|
5263
|
+
const entry = readModuleEntry(slug);
|
|
5264
|
+
if (!entry) {
|
|
5265
|
+
throw new Error(
|
|
5266
|
+
`No dev install cached for module "${slug}". Run \`dashwise init ${slug} --force\` to provision one.`
|
|
5267
|
+
);
|
|
5268
|
+
}
|
|
5269
|
+
return {
|
|
5270
|
+
installationId: entry.installationId,
|
|
5271
|
+
slug,
|
|
5272
|
+
requestOptions: {
|
|
5273
|
+
baseUrl: resolveApiUrl(),
|
|
5274
|
+
auth: { token: cfg.token }
|
|
5275
|
+
}
|
|
5276
|
+
};
|
|
5277
|
+
}
|
|
5278
|
+
async function apiKeysListCommand(options) {
|
|
5279
|
+
let ctx;
|
|
5280
|
+
try {
|
|
5281
|
+
ctx = loadContext(options);
|
|
5282
|
+
} catch (err) {
|
|
5283
|
+
fail(err.message);
|
|
5284
|
+
return 1;
|
|
5285
|
+
}
|
|
5286
|
+
let keys;
|
|
5287
|
+
try {
|
|
5288
|
+
const resp = await listApiKeys(ctx.installationId, ctx.requestOptions);
|
|
5289
|
+
keys = resp.api_keys;
|
|
5290
|
+
} catch (err) {
|
|
5291
|
+
return surfaceApiKeysError(err);
|
|
5292
|
+
}
|
|
5293
|
+
const filtered = options.all ? keys : keys.filter((k) => k.revoked_at === null);
|
|
5294
|
+
if (options.json) {
|
|
5295
|
+
process.stdout.write(`${JSON.stringify(filtered, null, 2)}
|
|
5296
|
+
`);
|
|
5297
|
+
return 0;
|
|
5298
|
+
}
|
|
5299
|
+
if (filtered.length === 0) {
|
|
5300
|
+
info(
|
|
5301
|
+
options.all ? `No API keys (active or revoked) for ${code(ctx.slug)}.` : `No active API keys for ${code(ctx.slug)}. Run ${code("dashwise api-keys create <name>")} to mint one, or ${code("dashwise api-keys list --all")} to include revoked.`
|
|
5302
|
+
);
|
|
5303
|
+
return 0;
|
|
5304
|
+
}
|
|
5305
|
+
info(`API keys for ${code(ctx.slug)} (install id=${ctx.installationId}):`);
|
|
5306
|
+
for (const k of filtered) {
|
|
5307
|
+
const status = formatKeyStatus(k);
|
|
5308
|
+
const lastUsed = k.last_used_at ? `last used ${formatRelative(new Date(k.last_used_at))}` : "never used";
|
|
5309
|
+
process.stdout.write(
|
|
5310
|
+
` ${code(`#${k.id}`)} ${k.name} ${dim(`dwk_${k.key_prefix}\u2026`)} ${status} ${dim(`(${lastUsed})`)}
|
|
5311
|
+
`
|
|
5312
|
+
);
|
|
5313
|
+
}
|
|
5314
|
+
return 0;
|
|
5315
|
+
}
|
|
5316
|
+
async function apiKeysCreateCommand(nameArg, options) {
|
|
5317
|
+
const name = nameArg ?? options.name;
|
|
5318
|
+
if (!name) {
|
|
5319
|
+
fail("Usage: `dashwise api-keys create <name>` (e.g. `dashwise api-keys create production`)");
|
|
5320
|
+
return 1;
|
|
5321
|
+
}
|
|
5322
|
+
let ctx;
|
|
5323
|
+
try {
|
|
5324
|
+
ctx = loadContext(options);
|
|
5325
|
+
} catch (err) {
|
|
5326
|
+
fail(err.message);
|
|
5327
|
+
return 1;
|
|
5328
|
+
}
|
|
5329
|
+
const body = { name };
|
|
5330
|
+
if (options.scopes !== void 0) {
|
|
5331
|
+
body.scopes = options.scopes.split(",").map((s) => s.trim()).filter(Boolean);
|
|
5332
|
+
}
|
|
5333
|
+
if (options.expiresAt !== void 0) {
|
|
5334
|
+
body.expires_at = options.expiresAt;
|
|
5335
|
+
}
|
|
5336
|
+
let resp;
|
|
5337
|
+
try {
|
|
5338
|
+
resp = await createApiKey(ctx.installationId, body, ctx.requestOptions);
|
|
5339
|
+
} catch (err) {
|
|
5340
|
+
return surfaceApiKeysError(err);
|
|
5341
|
+
}
|
|
5342
|
+
if (options.rawOnly) {
|
|
5343
|
+
process.stderr.write(
|
|
5344
|
+
`Created API key #${resp.api_key.id} (${resp.api_key.name}) for install ${ctx.installationId}.
|
|
5345
|
+
`
|
|
5346
|
+
);
|
|
5347
|
+
process.stdout.write(`${resp.raw_key}
|
|
5348
|
+
`);
|
|
5349
|
+
return 0;
|
|
5350
|
+
}
|
|
5351
|
+
success(
|
|
5352
|
+
`Created API key ${code(`#${resp.api_key.id}`)} (${resp.api_key.name}) for ${code(ctx.slug)}.`
|
|
5353
|
+
);
|
|
5354
|
+
info("");
|
|
5355
|
+
warn(
|
|
5356
|
+
"This is the ONLY time the full key is displayed. Save it now \u2014 the backend stores a hash, not the plaintext."
|
|
5357
|
+
);
|
|
5358
|
+
info("");
|
|
5359
|
+
process.stdout.write(` ${code(resp.raw_key)}
|
|
5360
|
+
`);
|
|
5361
|
+
info("");
|
|
5362
|
+
info(`Use in a deployed module's env:`);
|
|
5363
|
+
info(` ${code(`DASHWISE_API_KEY=${resp.raw_key.slice(0, 12)}\u2026`)}`);
|
|
5364
|
+
info(
|
|
5365
|
+
` ${code(`DASHWISE_INSTALLATION_ID=${ctx.installationId}`)}`
|
|
5366
|
+
);
|
|
5367
|
+
info(
|
|
5368
|
+
` ${code(`DASHWISE_API_URL=${resolveApiUrl()}`)}`
|
|
5369
|
+
);
|
|
5370
|
+
return 0;
|
|
5371
|
+
}
|
|
5372
|
+
async function apiKeysRevokeCommand(keyIdArg, options) {
|
|
5373
|
+
if (!keyIdArg) {
|
|
5374
|
+
fail("Usage: `dashwise api-keys revoke <key-id>` \u2014 id from `dashwise api-keys list`");
|
|
5375
|
+
return 1;
|
|
5376
|
+
}
|
|
5377
|
+
const keyId = Number.parseInt(keyIdArg, 10);
|
|
5378
|
+
if (!Number.isFinite(keyId) || keyId <= 0) {
|
|
5379
|
+
fail(`Invalid key id "${keyIdArg}" \u2014 expected a positive integer.`);
|
|
5380
|
+
return 1;
|
|
5381
|
+
}
|
|
5382
|
+
let ctx;
|
|
5383
|
+
try {
|
|
5384
|
+
ctx = loadContext(options);
|
|
5385
|
+
} catch (err) {
|
|
5386
|
+
fail(err.message);
|
|
5387
|
+
return 1;
|
|
5388
|
+
}
|
|
5389
|
+
if (!options.yes) {
|
|
5390
|
+
info(
|
|
5391
|
+
`Revoking API key #${keyId} for ${code(ctx.slug)} (install ${ctx.installationId}). Pass ${code("--yes")} to skip this confirmation in scripts.`
|
|
5392
|
+
);
|
|
5393
|
+
}
|
|
5394
|
+
let resp;
|
|
5395
|
+
try {
|
|
5396
|
+
resp = await revokeApiKey(ctx.installationId, keyId, ctx.requestOptions);
|
|
5397
|
+
} catch (err) {
|
|
5398
|
+
return surfaceApiKeysError(err);
|
|
5399
|
+
}
|
|
5400
|
+
success(
|
|
5401
|
+
`Revoked API key #${resp.api_key.id} (${resp.api_key.name}). Future requests with this key will return 401.`
|
|
5402
|
+
);
|
|
5403
|
+
return 0;
|
|
5404
|
+
}
|
|
5405
|
+
function surfaceApiKeysError(err) {
|
|
5406
|
+
if (err instanceof ApiError) {
|
|
5407
|
+
switch (err.code) {
|
|
5408
|
+
case "UNAUTHENTICATED":
|
|
5409
|
+
fail(
|
|
5410
|
+
`Auth rejected by backend. Your CLI token may be stale \u2014 run ${code("dashwise login")} then retry.`
|
|
5411
|
+
);
|
|
5412
|
+
return 1;
|
|
5413
|
+
case "NOT_WORKSPACE_MEMBER":
|
|
5414
|
+
fail(
|
|
5415
|
+
`You're not a member of this installation's workspace. API-key management requires workspace membership.`
|
|
5416
|
+
);
|
|
5417
|
+
return 1;
|
|
5418
|
+
case "INSTALLATION_NOT_FOUND":
|
|
5419
|
+
fail(
|
|
5420
|
+
`Installation not found. It may have been destroyed; re-provision via ${code("dashwise init <slug>")}.`
|
|
5421
|
+
);
|
|
5422
|
+
return 1;
|
|
5423
|
+
case "API_KEY_NOT_FOUND":
|
|
5424
|
+
fail(
|
|
5425
|
+
`API key not found for this installation. Use ${code("dashwise api-keys list")} to see valid ids.`
|
|
5426
|
+
);
|
|
5427
|
+
return 1;
|
|
5428
|
+
default:
|
|
5429
|
+
fail(`Backend rejected: ${err.code} ${err.status} \u2014 ${err.message}`);
|
|
5430
|
+
return 1;
|
|
5431
|
+
}
|
|
5432
|
+
}
|
|
5433
|
+
fail(`API-key operation failed: ${err.message}`);
|
|
5434
|
+
return 1;
|
|
5435
|
+
}
|
|
5436
|
+
function formatKeyStatus(k) {
|
|
5437
|
+
if (k.revoked_at) return dim("[revoked]");
|
|
5438
|
+
if (k.expires_at && new Date(k.expires_at).getTime() <= Date.now()) {
|
|
5439
|
+
return dim("[expired]");
|
|
5440
|
+
}
|
|
5441
|
+
return dim("[active]");
|
|
5442
|
+
}
|
|
5443
|
+
function formatRelative(d) {
|
|
5444
|
+
const deltaMs = Date.now() - d.getTime();
|
|
5445
|
+
const sec = Math.floor(deltaMs / 1e3);
|
|
5446
|
+
if (sec < 60) return `${sec}s ago`;
|
|
5447
|
+
const min = Math.floor(sec / 60);
|
|
5448
|
+
if (min < 60) return `${min}m ago`;
|
|
5449
|
+
const hr = Math.floor(min / 60);
|
|
5450
|
+
if (hr < 24) return `${hr}h ago`;
|
|
5451
|
+
const day = Math.floor(hr / 24);
|
|
5452
|
+
return `${day}d ago`;
|
|
5453
|
+
}
|
|
5454
|
+
|
|
5455
|
+
// src/commands/env-export.ts
|
|
5456
|
+
init_api_client();
|
|
5457
|
+
init_config();
|
|
5458
|
+
init_manifest_io();
|
|
5459
|
+
init_output();
|
|
5460
|
+
var PLACEHOLDER = "<run-`dashwise-api-keys-create-<name>`-and-paste-here>";
|
|
5461
|
+
async function envExportCommand(options) {
|
|
5462
|
+
const format = options.format ?? "env";
|
|
5463
|
+
if (!["env", "json", "railway", "vercel", "fly"].includes(format)) {
|
|
5464
|
+
fail(
|
|
5465
|
+
`Unknown --format "${format}". Allowed: env | json | railway | vercel | fly.`
|
|
5466
|
+
);
|
|
5467
|
+
return 1;
|
|
5468
|
+
}
|
|
5469
|
+
if (options.newKey && options.key) {
|
|
5470
|
+
fail(
|
|
5471
|
+
`Pass either --new-key (mint fresh) or --key (paste existing). Not both.`
|
|
5472
|
+
);
|
|
5473
|
+
return 1;
|
|
5474
|
+
}
|
|
5475
|
+
let manifest;
|
|
5476
|
+
try {
|
|
5477
|
+
manifest = readManifestOrThrow(options.dir);
|
|
5478
|
+
} catch (err) {
|
|
5479
|
+
fail(err.message);
|
|
5480
|
+
return 1;
|
|
5481
|
+
}
|
|
5482
|
+
const slug = manifest.module?.slug;
|
|
5483
|
+
if (!slug) {
|
|
5484
|
+
fail("module.json has no module.slug \u2014 the manifest is malformed.");
|
|
5485
|
+
return 1;
|
|
5486
|
+
}
|
|
5487
|
+
const cfg = readConfig();
|
|
5488
|
+
if (!cfg) {
|
|
5489
|
+
fail("Not logged in. Run `dashwise login` first.");
|
|
5490
|
+
return 1;
|
|
5491
|
+
}
|
|
5492
|
+
const entry = readModuleEntry(slug);
|
|
5493
|
+
if (!entry) {
|
|
5494
|
+
fail(
|
|
5495
|
+
`No dev install cached for module "${slug}". Run \`dashwise init ${slug} --force\` to provision one.`
|
|
5496
|
+
);
|
|
5497
|
+
return 1;
|
|
5498
|
+
}
|
|
5499
|
+
const apiUrl = resolveApiUrl();
|
|
5500
|
+
const installationId = entry.installationId;
|
|
5501
|
+
let apiKey;
|
|
5502
|
+
let apiKeyComment = null;
|
|
5503
|
+
if (options.key !== void 0) {
|
|
5504
|
+
if (!options.key.startsWith("dwk_")) {
|
|
5505
|
+
fail(`--key value must start with \`dwk_\` (got "${options.key.slice(0, 8)}\u2026").`);
|
|
5506
|
+
return 1;
|
|
5507
|
+
}
|
|
5508
|
+
apiKey = options.key;
|
|
5509
|
+
apiKeyComment = "# DASHWISE_API_KEY supplied via --key";
|
|
5510
|
+
} else if (options.newKey !== void 0) {
|
|
5511
|
+
try {
|
|
5512
|
+
const resp = await createApiKey(
|
|
5513
|
+
installationId,
|
|
5514
|
+
{ name: options.newKey },
|
|
5515
|
+
{
|
|
5516
|
+
baseUrl: apiUrl,
|
|
5517
|
+
auth: { token: cfg.token }
|
|
5518
|
+
}
|
|
5519
|
+
);
|
|
5520
|
+
apiKey = resp.raw_key;
|
|
5521
|
+
apiKeyComment = `# DASHWISE_API_KEY minted by --new-key (id=${resp.api_key.id}, name="${resp.api_key.name}")`;
|
|
5522
|
+
process.stderr.write(
|
|
5523
|
+
`${dim("[env export]")} Minted API key #${resp.api_key.id} (${resp.api_key.name}). The plaintext below is the ONLY time it's shown \u2014 save the file or paste it now.
|
|
5524
|
+
`
|
|
5525
|
+
);
|
|
5526
|
+
} catch (err) {
|
|
5527
|
+
if (err instanceof ApiError) {
|
|
5528
|
+
fail(`Failed to mint API key: ${err.code} ${err.status} \u2014 ${err.message}`);
|
|
5529
|
+
} else {
|
|
5530
|
+
fail(`Failed to mint API key: ${err.message}`);
|
|
5531
|
+
}
|
|
5532
|
+
return 1;
|
|
5533
|
+
}
|
|
5534
|
+
} else {
|
|
5535
|
+
apiKey = PLACEHOLDER;
|
|
5536
|
+
apiKeyComment = "# DASHWISE_API_KEY \u2014 run `dashwise api-keys create <name>` to mint one + paste here.";
|
|
5537
|
+
}
|
|
5538
|
+
const entries = [
|
|
5539
|
+
{
|
|
5540
|
+
key: "DASHWISE_API_URL",
|
|
5541
|
+
value: apiUrl,
|
|
5542
|
+
comment: "# DashWise backend URL \u2014 same value the CLI is logged into."
|
|
5543
|
+
},
|
|
5544
|
+
{
|
|
5545
|
+
key: "NEXT_PUBLIC_DASHWISE_API_URL",
|
|
5546
|
+
value: apiUrl,
|
|
5547
|
+
comment: "# Client-side mirror \u2014 Next.js inlines NEXT_PUBLIC_* into the browser bundle so <AuthProvider> hits the right origin."
|
|
5548
|
+
},
|
|
5549
|
+
{
|
|
5550
|
+
key: "DASHWISE_INSTALLATION_ID",
|
|
5551
|
+
value: String(installationId),
|
|
5552
|
+
comment: `# Per-workspace install id for module "${slug}".`
|
|
5553
|
+
},
|
|
5554
|
+
{
|
|
5555
|
+
key: "DASHWISE_API_KEY",
|
|
5556
|
+
value: apiKey,
|
|
5557
|
+
...apiKeyComment !== null ? { comment: apiKeyComment } : {}
|
|
5558
|
+
}
|
|
5559
|
+
];
|
|
5560
|
+
process.stdout.write(render(entries, format));
|
|
5561
|
+
if (format !== "json") process.stdout.write("\n");
|
|
5562
|
+
if (apiKey === PLACEHOLDER) {
|
|
5563
|
+
info("");
|
|
5564
|
+
info(
|
|
5565
|
+
`Next: ${code(`dashwise api-keys create <name>`)} \u2192 paste the plaintext into ${code("DASHWISE_API_KEY")}.`
|
|
5566
|
+
);
|
|
5567
|
+
} else if (options.newKey !== void 0) {
|
|
5568
|
+
info("");
|
|
5569
|
+
warn(
|
|
5570
|
+
"API key plaintext is shown ONLY once. Save the output of this command now."
|
|
5571
|
+
);
|
|
5572
|
+
}
|
|
5573
|
+
return 0;
|
|
5574
|
+
}
|
|
5575
|
+
function render(entries, format) {
|
|
5576
|
+
switch (format) {
|
|
5577
|
+
case "env": {
|
|
5578
|
+
const lines = [];
|
|
5579
|
+
for (const e of entries) {
|
|
5580
|
+
if (e.comment) lines.push(e.comment);
|
|
5581
|
+
lines.push(`${e.key}=${e.value}`);
|
|
5582
|
+
lines.push("");
|
|
5583
|
+
}
|
|
5584
|
+
return lines.join("\n").trimEnd();
|
|
5585
|
+
}
|
|
5586
|
+
case "json": {
|
|
5587
|
+
const obj = {};
|
|
5588
|
+
for (const e of entries) obj[e.key] = e.value;
|
|
5589
|
+
return JSON.stringify(obj, null, 2);
|
|
5590
|
+
}
|
|
5591
|
+
case "railway": {
|
|
5592
|
+
const parts = entries.map((e) => `${e.key}='${e.value.replace(/'/g, "'\\''")}'`);
|
|
5593
|
+
return `railway variables set ${parts.join(" ")}`;
|
|
5594
|
+
}
|
|
5595
|
+
case "vercel": {
|
|
5596
|
+
const lines = entries.map(
|
|
5597
|
+
(e) => `echo ${shellQuote(e.value)} | vercel env add ${e.key} production`
|
|
5598
|
+
);
|
|
5599
|
+
return lines.join("\n");
|
|
5600
|
+
}
|
|
5601
|
+
case "fly": {
|
|
5602
|
+
const parts = entries.map((e) => `${e.key}=${shellQuote(e.value)}`);
|
|
5603
|
+
return `fly secrets set ${parts.join(" ")}`;
|
|
5604
|
+
}
|
|
5605
|
+
}
|
|
5606
|
+
}
|
|
5607
|
+
function shellQuote(value) {
|
|
5608
|
+
return `'${value.replace(/'/g, "'\\''")}'`;
|
|
5609
|
+
}
|
|
5610
|
+
|
|
5033
5611
|
// src/commands/query.ts
|
|
5034
5612
|
init_manifest_io();
|
|
5035
5613
|
init_output();
|
|
@@ -5635,7 +6213,14 @@ program.command("dev").description(
|
|
|
5635
6213
|
).option(
|
|
5636
6214
|
"--api-url <url>",
|
|
5637
6215
|
"Override the `DASHWISE_API_URL` env var passed to children (default: saved CLI config)."
|
|
5638
|
-
).option("--port <number>", "Port for `next dev` (default: 3000).", parseIntOption).option("--sdk-only", "Only run the manifest watcher; skip `next dev`.").option("--next-only", "Only run `next dev`; skip the manifest watcher.").
|
|
6216
|
+
).option("--port <number>", "Port for `next dev` (default: 3000).", parseIntOption).option("--sdk-only", "Only run the manifest watcher; skip `next dev`.").option("--next-only", "Only run `next dev`; skip the manifest watcher.").option(
|
|
6217
|
+
"--no-remote-poll",
|
|
6218
|
+
"Disable periodic backend manifest polling. By default, `dashwise dev` polls `GET /api/installations/:id/schema` every few seconds + writes module.json when the backend has advanced (dashboard edits, AI builder mutations, teammate commands)."
|
|
6219
|
+
).option(
|
|
6220
|
+
"--remote-poll-interval <seconds>",
|
|
6221
|
+
"Backend manifest poll interval, in seconds. Default: 5. Minimum: 1.",
|
|
6222
|
+
parseIntOption
|
|
6223
|
+
).action(
|
|
5639
6224
|
async (cmdOpts) => {
|
|
5640
6225
|
process.exitCode = await devCommand({
|
|
5641
6226
|
...cmdOpts.dir !== void 0 ? { dir: cmdOpts.dir } : {},
|
|
@@ -5645,7 +6230,11 @@ program.command("dev").description(
|
|
|
5645
6230
|
...cmdOpts.apiUrl !== void 0 ? { apiUrl: cmdOpts.apiUrl } : {},
|
|
5646
6231
|
...cmdOpts.port !== void 0 ? { port: cmdOpts.port } : {},
|
|
5647
6232
|
...cmdOpts.sdkOnly !== void 0 ? { sdkOnly: cmdOpts.sdkOnly } : {},
|
|
5648
|
-
...cmdOpts.nextOnly !== void 0 ? { nextOnly: cmdOpts.nextOnly } : {}
|
|
6233
|
+
...cmdOpts.nextOnly !== void 0 ? { nextOnly: cmdOpts.nextOnly } : {},
|
|
6234
|
+
// Commander's --no-foo flag maps to `foo: false`. devCommand's
|
|
6235
|
+
// option is `noRemotePoll: boolean` — invert to map cleanly.
|
|
6236
|
+
...cmdOpts.remotePoll === false ? { noRemotePoll: true } : {},
|
|
6237
|
+
...cmdOpts.remotePollInterval !== void 0 ? { remotePollIntervalSec: cmdOpts.remotePollInterval } : {}
|
|
5649
6238
|
});
|
|
5650
6239
|
}
|
|
5651
6240
|
);
|
|
@@ -5797,6 +6386,80 @@ program.command("query").description(
|
|
|
5797
6386
|
});
|
|
5798
6387
|
}
|
|
5799
6388
|
);
|
|
6389
|
+
program.command("pull").description(
|
|
6390
|
+
"Sync local module.json from the backend. Fetches the canonical manifest for the current install and writes it to disk. Inverse of `dashwise table/field` commands."
|
|
6391
|
+
).option("--dir <path>", "Project root containing `module.json` (default: current directory).").option("--dry-run", "Fetch + report drift but do not write to module.json.").action(async (cmdOpts) => {
|
|
6392
|
+
process.exitCode = await pullCommand({
|
|
6393
|
+
...cmdOpts.dir !== void 0 ? { dir: cmdOpts.dir } : {},
|
|
6394
|
+
...cmdOpts.dryRun !== void 0 ? { dryRun: cmdOpts.dryRun } : {}
|
|
6395
|
+
});
|
|
6396
|
+
});
|
|
6397
|
+
var apiKeysCmd = program.command("api-keys").description(
|
|
6398
|
+
"Manage per-installation API keys (`dwk_*`). Pasted into a deployed module's env for production data-plane auth."
|
|
6399
|
+
);
|
|
6400
|
+
apiKeysCmd.command("list").description(
|
|
6401
|
+
"List API keys for the current module's installation. Active only by default; pass --all for revoked too."
|
|
6402
|
+
).option("--dir <path>", "Project root (default: current directory).").option("--all", "Include revoked + expired keys in the output.").option("--json", "Emit JSON instead of the human-friendly table.").action(async (cmdOpts) => {
|
|
6403
|
+
process.exitCode = await apiKeysListCommand({
|
|
6404
|
+
...cmdOpts.dir !== void 0 ? { dir: cmdOpts.dir } : {},
|
|
6405
|
+
...cmdOpts.all !== void 0 ? { all: cmdOpts.all } : {},
|
|
6406
|
+
...cmdOpts.json !== void 0 ? { json: cmdOpts.json } : {}
|
|
6407
|
+
});
|
|
6408
|
+
});
|
|
6409
|
+
apiKeysCmd.command("create [name]").description(
|
|
6410
|
+
"Mint a new API key. The plaintext key is displayed ONCE \u2014 save it then."
|
|
6411
|
+
).option("--dir <path>", "Project root (default: current directory).").option("--name <name>", "Override the positional name arg (e.g. for scripted use).").option(
|
|
6412
|
+
"--scopes <csv>",
|
|
6413
|
+
"Comma-separated scope strings (e.g. `runtime:read,runtime:write`). Default: full install access."
|
|
6414
|
+
).option(
|
|
6415
|
+
"--expires-at <iso>",
|
|
6416
|
+
"ISO-8601 expiry timestamp (e.g. 2026-12-31T23:59:59Z). Default: never expires."
|
|
6417
|
+
).option(
|
|
6418
|
+
"--raw-only",
|
|
6419
|
+
"Print only the plaintext key on stdout; chatter goes to stderr. Useful for shell capture: `KEY=$(dashwise api-keys create prod --raw-only)`"
|
|
6420
|
+
).action(
|
|
6421
|
+
async (nameArg, cmdOpts) => {
|
|
6422
|
+
process.exitCode = await apiKeysCreateCommand(nameArg, {
|
|
6423
|
+
...cmdOpts.dir !== void 0 ? { dir: cmdOpts.dir } : {},
|
|
6424
|
+
...cmdOpts.name !== void 0 ? { name: cmdOpts.name } : {},
|
|
6425
|
+
...cmdOpts.scopes !== void 0 ? { scopes: cmdOpts.scopes } : {},
|
|
6426
|
+
...cmdOpts.expiresAt !== void 0 ? { expiresAt: cmdOpts.expiresAt } : {},
|
|
6427
|
+
...cmdOpts.rawOnly !== void 0 ? { rawOnly: cmdOpts.rawOnly } : {}
|
|
6428
|
+
});
|
|
6429
|
+
}
|
|
6430
|
+
);
|
|
6431
|
+
apiKeysCmd.command("revoke [key-id]").description(
|
|
6432
|
+
"Soft-revoke an API key. Backend keeps the row for audit; further requests return 401."
|
|
6433
|
+
).option("--dir <path>", "Project root (default: current directory).").option("-y, --yes", "Skip the per-key confirmation message (for CI / scripts).").action(
|
|
6434
|
+
async (keyIdArg, cmdOpts) => {
|
|
6435
|
+
process.exitCode = await apiKeysRevokeCommand(keyIdArg, {
|
|
6436
|
+
...cmdOpts.dir !== void 0 ? { dir: cmdOpts.dir } : {},
|
|
6437
|
+
...cmdOpts.yes !== void 0 ? { yes: cmdOpts.yes } : {}
|
|
6438
|
+
});
|
|
6439
|
+
}
|
|
6440
|
+
);
|
|
6441
|
+
var envCmd = program.command("env").description("Environment-variable helpers for deploying a module.");
|
|
6442
|
+
envCmd.command("export").description(
|
|
6443
|
+
"Emit the env vars a deployed module needs to authenticate against DashWise. By default emits .env-style KEY=value lines; --format = env | json | railway | vercel | fly to wrap in platform-native syntax. Use --new-key <name> to mint + inline an API key in one step."
|
|
6444
|
+
).option("--dir <path>", "Project root (default: current directory).").option(
|
|
6445
|
+
"--format <fmt>",
|
|
6446
|
+
"Output format: env | json | railway | vercel | fly (default: env)."
|
|
6447
|
+
).option(
|
|
6448
|
+
"--new-key <name>",
|
|
6449
|
+
"Mint a fresh API key with this name and inline the plaintext. (Mutually exclusive with --key.)"
|
|
6450
|
+
).option(
|
|
6451
|
+
"--key <dwk_value>",
|
|
6452
|
+
"Use a previously-minted API key (paste plaintext). (Mutually exclusive with --new-key.)"
|
|
6453
|
+
).action(
|
|
6454
|
+
async (cmdOpts) => {
|
|
6455
|
+
process.exitCode = await envExportCommand({
|
|
6456
|
+
...cmdOpts.dir !== void 0 ? { dir: cmdOpts.dir } : {},
|
|
6457
|
+
...cmdOpts.format !== void 0 ? { format: cmdOpts.format } : {},
|
|
6458
|
+
...cmdOpts.newKey !== void 0 ? { newKey: cmdOpts.newKey } : {},
|
|
6459
|
+
...cmdOpts.key !== void 0 ? { key: cmdOpts.key } : {}
|
|
6460
|
+
});
|
|
6461
|
+
}
|
|
6462
|
+
);
|
|
5800
6463
|
moduleCmd.command("publish").description("Pack the current directory + upload it as a new module version.").option("--dir <path>", "Project root (default: current directory).").option("--bump <direction>", "Semver bump: patch | minor | major.").option("--dry-run", "Validate + upload but do not persist the version row.").option("-y, --yes", "Skip the confirmation prompt (for CI / scripted use).").option(
|
|
5801
6464
|
"--exclude <pattern...>",
|
|
5802
6465
|
"Extra exclude patterns (segment-matched) appended to the defaults."
|
|
@@ -5988,7 +6651,7 @@ fieldCmd.command("set-type <table-slug> <field-slug> <new-type>").description(
|
|
|
5988
6651
|
}
|
|
5989
6652
|
})();
|
|
5990
6653
|
function getVersion() {
|
|
5991
|
-
return "0.
|
|
6654
|
+
return "0.5.0";
|
|
5992
6655
|
}
|
|
5993
6656
|
function parseIntOption(value) {
|
|
5994
6657
|
const n = Number.parseInt(value, 10);
|