rainskills 0.1.19 → 0.1.21

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.
Files changed (40) hide show
  1. package/README.md +34 -39
  2. package/SKILL.md +12 -10
  3. package/bin/rainskills-tools.js +114 -240
  4. package/bin/rainskills.js +134 -591
  5. package/install.sh +68 -94
  6. package/marketplace/rainskills/.claude-plugin/plugin.json +1 -1
  7. package/marketplace/rainskills/.codex-plugin/plugin.json +1 -1
  8. package/marketplace/rainskills/skills/rainskills/SKILL.md +13 -11
  9. package/package.json +2 -2
  10. package/rainbond-app-assistant/SKILL.md +116 -151
  11. package/rainbond-app-version-assistant/SKILL.md +98 -98
  12. package/rainbond-delivery-verifier/SKILL.md +98 -68
  13. package/rainbond-env-sync/SKILL.md +98 -69
  14. package/rainbond-fullstack-bootstrap/SKILL.md +101 -89
  15. package/rainbond-fullstack-bootstrap/modules/10-context-loading.md +1 -1
  16. package/rainbond-fullstack-troubleshooter/SKILL.md +98 -68
  17. package/rainbond-opensource-app-deploy/SKILL.md +102 -81
  18. package/rainbond-platform-installer/SKILL.md +4 -4
  19. package/rainbond-platform-installer/scripts/auto-update.js +0 -9
  20. package/rainbond-platform-installer/scripts/installed-version.js +1 -1
  21. package/rainbond-platform-installer/scripts/platform-installer.js +3 -89
  22. package/rainbond-platform-installer/scripts/runtime-state.js +14 -251
  23. package/rainbond-platform-installer/scripts/single-runtime.js +114 -0
  24. package/rainbond-platform-installer/scripts/user-message.js +3 -49
  25. package/rainbond-platform-installer/scripts/windows-client-config.js +0 -51
  26. package/rainbond-platform-installer/scripts/windows-onboarding.js +0 -3
  27. package/rainbond-platform-installer/scripts/windows-platform.ps1 +1 -1
  28. package/rainbond-platform-query/SKILL.md +103 -61
  29. package/rainbond-project-init/SKILL.md +102 -79
  30. package/rainbond-template-installer/SKILL.md +102 -80
  31. package/rainbond-platform-installer/scripts/environment-credentials.js +0 -225
  32. package/rainbond-platform-installer/scripts/environment-registry.js +0 -349
  33. package/rainbond-platform-installer/scripts/local-runtime-commands.js +0 -180
  34. package/rainbond-platform-installer/scripts/local-runtime.js +0 -58
  35. package/rainbond-platform-installer/scripts/runtime-context-resolver.js +0 -189
  36. package/rainbond-platform-installer/scripts/runtime-credentials.js +0 -163
  37. package/rainbond-platform-installer/scripts/runtime-intents.js +0 -386
  38. package/rainbond-platform-installer/scripts/runtime-operations.js +0 -597
  39. package/rainbond-platform-installer/scripts/windows-client-config.ps1 +0 -9
  40. package/rainbond-platform-installer/scripts/windows-read-user-environment.ps1 +0 -16
@@ -1,597 +0,0 @@
1
- "use strict";
2
-
3
- const fs = require("node:fs");
4
- const os = require("node:os");
5
- const path = require("node:path");
6
- const { isDeepStrictEqual } = require("node:util");
7
-
8
- const { createSecureStateStore } = require("./secure-state.js");
9
- const { INTENT_DEFINITIONS, validateIntent } = require("./runtime-intents.js");
10
-
11
- const OPERATION_SCHEMA_V1 = "rainskills.runtime-operation.v1";
12
- const OPERATION_SCHEMA = "rainskills.runtime-operation.v2";
13
- const UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
14
- const CONTROL_PATTERN = /[\u0000-\u001f\u007f-\u009f]/u;
15
- const STAGES = new Set(["awaiting-environment", "active", "interrupted", "completed"]);
16
- const ACTIVE_STAGES = new Set(["awaiting-environment", "active", "interrupted"]);
17
- const FAILURE_CATEGORIES = new Set(["credential-expired", "permission-denied"]);
18
- const OPERATION_FIELDS_V1 = new Set([
19
- "schema", "version", "operation_id", "environment_id", "intent",
20
- "team_id", "app_id", "service_id", "stage", "failed_step",
21
- "retry_count", "retry_budget", "last_failure_category",
22
- "created_at", "updated_at",
23
- ]);
24
- const OPERATION_FIELDS = new Set([
25
- "schema", "version", "operation_id", "environment_id", "intent",
26
- "context", "context_revision", "pending_selection", "stage", "failed_step",
27
- "retry_count", "retry_budget", "last_failure_category",
28
- "created_at", "updated_at",
29
- ]);
30
- const CONTEXT_FIELDS = new Set([
31
- "enterprise_id", "team_id", "team_name", "region_name", "app_id", "app_name",
32
- "service_id", "service_name", "created_services", "template_source", "market_name",
33
- "app_model_id", "app_model_version", "snapshot_version_id",
34
- ]);
35
-
36
- function emptyContext() {
37
- return {
38
- enterprise_id: null,
39
- team_id: null,
40
- team_name: null,
41
- region_name: null,
42
- app_id: null,
43
- app_name: null,
44
- service_id: null,
45
- service_name: null,
46
- created_services: {},
47
- template_source: null,
48
- market_name: null,
49
- app_model_id: null,
50
- app_model_version: null,
51
- snapshot_version_id: null,
52
- };
53
- }
54
-
55
- function isIsoTimestamp(value) {
56
- return typeof value === "string"
57
- && /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{3})?Z$/.test(value)
58
- && !Number.isNaN(Date.parse(value));
59
- }
60
-
61
- function assertUuid(value, label) {
62
- if (!UUID_PATTERN.test(value || "")) throw new Error(`${label}无效`);
63
- return value;
64
- }
65
-
66
- function normalizeIdentifier(value, label) {
67
- if (value === null || value === undefined) return null;
68
- if (
69
- typeof value !== "string"
70
- || !value
71
- || value.length > 128
72
- || CONTROL_PATTERN.test(value)
73
- ) {
74
- throw new Error(`${label}无效`);
75
- }
76
- return value;
77
- }
78
-
79
- function clone(value) {
80
- return JSON.parse(JSON.stringify(value));
81
- }
82
-
83
- function validateContext(input) {
84
- if (!input || typeof input !== "object" || Array.isArray(input)) {
85
- throw new Error("runtime operation context 无效");
86
- }
87
- if (Object.keys(input).length !== CONTEXT_FIELDS.size) {
88
- throw new Error("runtime operation context schema 无效");
89
- }
90
- for (const field of Object.keys(input)) {
91
- if (!CONTEXT_FIELDS.has(field)) throw new Error(`runtime operation context 包含未知字段:${field}`);
92
- }
93
- const context = emptyContext();
94
- for (const field of CONTEXT_FIELDS) {
95
- if (field === "created_services") continue;
96
- context[field] = normalizeIdentifier(input[field], `context ${field}`);
97
- }
98
- if (!input.created_services || typeof input.created_services !== "object" || Array.isArray(input.created_services)) {
99
- throw new Error("runtime operation created_services 无效");
100
- }
101
- context.created_services = {};
102
- for (const [logicalName, service] of Object.entries(input.created_services)) {
103
- const normalizedName = normalizeIdentifier(logicalName, "logical service name");
104
- if (!service || typeof service !== "object" || Array.isArray(service)
105
- || !Object.hasOwn(service, "service_id") || !Object.hasOwn(service, "service_name")
106
- || Object.keys(service).length !== 2) {
107
- throw new Error("runtime operation created service 无效");
108
- }
109
- context.created_services[normalizedName] = {
110
- service_id: normalizeIdentifier(service.service_id, "created service_id"),
111
- service_name: normalizeIdentifier(service.service_name, "created service_name"),
112
- };
113
- }
114
- return context;
115
- }
116
-
117
- function validatePendingSelection(input) {
118
- if (input === null) return null;
119
- if (!input || typeof input !== "object" || Array.isArray(input)) {
120
- throw new Error("runtime operation pending selection 无效");
121
- }
122
- const allowed = new Set(["selection_id", "dimension", "options", "context_revision"]);
123
- for (const field of Object.keys(input)) {
124
- if (!allowed.has(field)) throw new Error(`runtime operation pending selection 包含未知字段:${field}`);
125
- }
126
- assertUuid(input.selection_id, "selection_id ");
127
- const dimension = normalizeIdentifier(input.dimension, "selection dimension");
128
- if (!Array.isArray(input.options) || input.options.length < 1 || input.options.length > 256) {
129
- throw new Error("runtime operation selection options 无效");
130
- }
131
- const options = input.options.map((option) => {
132
- if (!option || typeof option !== "object" || Array.isArray(option)) {
133
- throw new Error("runtime operation selection option 无效");
134
- }
135
- return {
136
- id: assertUuid(option.id, "selection option id "),
137
- label: normalizeIdentifier(option.label, "selection option label"),
138
- team_id: normalizeIdentifier(option.team_id, "selection team_id"),
139
- team_name: normalizeIdentifier(option.team_name, "selection team_name"),
140
- region_name: normalizeIdentifier(option.region_name, "selection region_name"),
141
- };
142
- });
143
- if (!Number.isInteger(input.context_revision) || input.context_revision < 0) {
144
- throw new Error("runtime operation selection revision 无效");
145
- }
146
- return {
147
- selection_id: input.selection_id,
148
- dimension,
149
- options,
150
- context_revision: input.context_revision,
151
- };
152
- }
153
-
154
- function createRuntimeOperationStore({
155
- platform = process.platform,
156
- home = os.homedir(),
157
- stateStore = createSecureStateStore({ platform, home }),
158
- registry,
159
- now = () => new Date().toISOString(),
160
- } = {}) {
161
- if (!registry || typeof registry.read !== "function" || typeof registry.get !== "function") {
162
- throw new Error("runtime operation 缺少环境注册表");
163
- }
164
- const directory = path.join(home, ".rainbond", "rainskills", "operations");
165
-
166
- function pathFor(operationId) {
167
- return path.join(directory, `${assertUuid(operationId, "operation_id ")}.json`);
168
- }
169
-
170
- function validateOperationCommon(input, expectedFields, schema, version) {
171
- if (!input || typeof input !== "object" || Array.isArray(input)) {
172
- throw new Error("runtime operation 无效");
173
- }
174
- for (const field of Object.keys(input)) {
175
- if (!expectedFields.has(field)) throw new Error(`runtime operation 包含未知字段:${field}`);
176
- }
177
- if (
178
- Object.keys(input).length !== expectedFields.size
179
- || input.schema !== schema
180
- || input.version !== version
181
- || !STAGES.has(input.stage)
182
- ) {
183
- throw new Error("runtime operation schema 无效");
184
- }
185
- const operationId = assertUuid(input.operation_id, "operation_id ");
186
- let environmentId = input.environment_id;
187
- if (input.stage === "awaiting-environment") {
188
- if (environmentId !== null) throw new Error("等待环境的操作不能提前绑定环境");
189
- } else {
190
- environmentId = assertUuid(environmentId, "environment_id ");
191
- }
192
- const intent = validateIntent(input.intent);
193
- const steps = INTENT_DEFINITIONS[intent.type].steps;
194
- if (input.failed_step !== null && !steps.includes(input.failed_step)) {
195
- throw new Error("runtime operation failed_step 无效");
196
- }
197
- if (!Number.isInteger(input.retry_count) || input.retry_count < 0) {
198
- throw new Error("runtime operation retry_count 无效");
199
- }
200
- if (![0, 1].includes(input.retry_budget)) throw new Error("runtime operation retry_budget 无效");
201
- if (input.last_failure_category !== null && !FAILURE_CATEGORIES.has(input.last_failure_category)) {
202
- throw new Error("runtime operation failure category 无效");
203
- }
204
- if (!isIsoTimestamp(input.created_at) || !isIsoTimestamp(input.updated_at)) {
205
- throw new Error("runtime operation timestamp 无效");
206
- }
207
- return {
208
- operation_id: operationId,
209
- environment_id: environmentId,
210
- intent,
211
- stage: input.stage,
212
- failed_step: input.failed_step,
213
- retry_count: input.retry_count,
214
- retry_budget: input.retry_budget,
215
- last_failure_category: input.last_failure_category,
216
- created_at: input.created_at,
217
- updated_at: input.updated_at,
218
- };
219
- }
220
-
221
- function validateLegacyOperation(input) {
222
- const common = validateOperationCommon(input, OPERATION_FIELDS_V1, OPERATION_SCHEMA_V1, 1);
223
- return {
224
- schema: OPERATION_SCHEMA_V1,
225
- version: 1,
226
- ...common,
227
- team_id: normalizeIdentifier(input.team_id, "team_id"),
228
- app_id: normalizeIdentifier(input.app_id, "app_id"),
229
- service_id: normalizeIdentifier(input.service_id, "service_id"),
230
- };
231
- }
232
-
233
- function validateStoredOperation(input) {
234
- if (input?.schema === OPERATION_SCHEMA_V1 || input?.version === 1) {
235
- return validateLegacyOperation(input);
236
- }
237
- const common = validateOperationCommon(input, OPERATION_FIELDS, OPERATION_SCHEMA, 2);
238
- if (!Number.isInteger(input.context_revision) || input.context_revision < 0) {
239
- throw new Error("runtime operation context revision 无效");
240
- }
241
- return {
242
- schema: OPERATION_SCHEMA,
243
- version: 2,
244
- ...common,
245
- context: validateContext(input.context),
246
- context_revision: input.context_revision,
247
- pending_selection: validatePendingSelection(input.pending_selection),
248
- };
249
- }
250
-
251
- function migrateLegacyOperation(legacy) {
252
- if (legacy.intent.template_id || legacy.intent.snapshot_id) {
253
- throw new Error("runtime-operation-migration-blocked");
254
- }
255
- return {
256
- schema: OPERATION_SCHEMA,
257
- version: 2,
258
- operation_id: legacy.operation_id,
259
- environment_id: legacy.environment_id,
260
- intent: legacy.intent,
261
- context: {
262
- ...emptyContext(),
263
- team_id: legacy.team_id,
264
- app_id: legacy.app_id,
265
- service_id: legacy.service_id,
266
- },
267
- context_revision: 0,
268
- pending_selection: null,
269
- stage: legacy.stage,
270
- failed_step: legacy.failed_step,
271
- retry_count: legacy.retry_count,
272
- retry_budget: legacy.retry_budget,
273
- last_failure_category: legacy.last_failure_category,
274
- created_at: legacy.created_at,
275
- updated_at: legacy.updated_at,
276
- };
277
- }
278
-
279
- function readRaw(operationId) {
280
- const target = pathFor(operationId);
281
- if (!fs.existsSync(target)) return null;
282
- return clone(validateStoredOperation(stateStore.readProtectedJson(target)));
283
- }
284
-
285
- function writeUnlocked(operation) {
286
- const validated = validateStoredOperation(operation);
287
- if (validated.version !== 2) throw new Error("runtime operation 只允许写入 v2");
288
- stateStore.ensurePrivateDirectory(directory);
289
- stateStore.atomicWriteJson(pathFor(validated.operation_id), validated);
290
- return clone(validated);
291
- }
292
-
293
- function withLock(operationId, action) {
294
- let lock;
295
- try {
296
- lock = stateStore.acquireOperationLock({ operationId: assertUuid(operationId, "operation_id ") });
297
- } catch (error) {
298
- if (error?.code === "RAINSKILLS_OPERATION_LOCK_BUSY") {
299
- throw new Error("runtime operation 正在由另一个进程更新");
300
- }
301
- throw new Error("runtime operation 本地受保护状态不可用,禁止自动重试;请重新安装 Rainskills 后再执行原始操作");
302
- }
303
- try {
304
- return action();
305
- } finally {
306
- lock.release();
307
- }
308
- }
309
-
310
- function readUnlocked(operationId) {
311
- const current = readRaw(operationId);
312
- if (!current || current.version === 2) return current;
313
- return writeUnlocked(migrateLegacyOperation(current));
314
- }
315
-
316
- function read(operationId) {
317
- const current = readRaw(operationId);
318
- if (!current || current.version === 2) return current;
319
- return withLock(operationId, () => readUnlocked(operationId));
320
- }
321
-
322
- function initialOperation({ operationId, environmentId, intent, stage }) {
323
- const timestamp = now();
324
- return {
325
- schema: OPERATION_SCHEMA,
326
- version: 2,
327
- operation_id: operationId,
328
- environment_id: environmentId,
329
- intent: validateIntent(intent),
330
- context: emptyContext(),
331
- context_revision: 0,
332
- pending_selection: null,
333
- stage,
334
- failed_step: null,
335
- retry_count: 0,
336
- retry_budget: 0,
337
- last_failure_category: null,
338
- created_at: timestamp,
339
- updated_at: timestamp,
340
- };
341
- }
342
-
343
- function createPending({ operationId, intent } = {}) {
344
- return withLock(operationId, () => {
345
- const existing = readUnlocked(operationId);
346
- const requested = initialOperation({
347
- operationId,
348
- environmentId: null,
349
- intent,
350
- stage: "awaiting-environment",
351
- });
352
- if (existing) {
353
- if (
354
- existing.stage === "awaiting-environment"
355
- && isDeepStrictEqual(existing.intent, requested.intent)
356
- ) return existing;
357
- throw new Error("operation_id 已用于其他任务");
358
- }
359
- return writeUnlocked(requested);
360
- });
361
- }
362
-
363
- function assertConnectedEnvironment(environmentId) {
364
- const environment = registry.get(assertUuid(environmentId, "environment_id "));
365
- if (!environment) throw new Error("运行环境不存在");
366
- if (environment.connection_state !== "connected") throw new Error("运行环境当前不可用");
367
- return environment;
368
- }
369
-
370
- function begin({ operationId, environmentId, intent } = {}) {
371
- const registryState = registry.read();
372
- const resolvedId = environmentId || registryState.default_environment_id;
373
- if (!resolvedId) throw new Error("目前还没有可用的应用运行环境");
374
- assertConnectedEnvironment(resolvedId);
375
- return withLock(operationId, () => {
376
- const existing = readUnlocked(operationId);
377
- const requested = initialOperation({
378
- operationId,
379
- environmentId: resolvedId,
380
- intent,
381
- stage: "active",
382
- });
383
- if (existing) {
384
- if (
385
- existing.environment_id === resolvedId
386
- && isDeepStrictEqual(existing.intent, requested.intent)
387
- ) return existing;
388
- throw new Error("operation_id 已用于其他任务");
389
- }
390
- return writeUnlocked(requested);
391
- });
392
- }
393
-
394
- function bindEnvironment(operationId, environmentId) {
395
- assertConnectedEnvironment(environmentId);
396
- return withLock(operationId, () => {
397
- const current = readUnlocked(operationId);
398
- if (!current) throw new Error("runtime operation 不存在");
399
- if (current.environment_id !== null) throw new Error("runtime operation 已经锁定运行环境");
400
- if (current.stage !== "awaiting-environment") throw new Error("runtime operation 当前不能绑定环境");
401
- return writeUnlocked({
402
- ...current,
403
- environment_id: environmentId,
404
- stage: "active",
405
- updated_at: now(),
406
- });
407
- });
408
- }
409
-
410
- function updateTargets(operationId, { teamId, appId, serviceId } = {}) {
411
- const current = read(operationId);
412
- if (!current) throw new Error("runtime operation 不存在");
413
- return updateContext(operationId, {
414
- expectedRevision: current.context_revision,
415
- values: {
416
- ...(teamId === undefined ? {} : { team_id: teamId }),
417
- ...(appId === undefined ? {} : { app_id: appId }),
418
- ...(serviceId === undefined ? {} : { service_id: serviceId }),
419
- },
420
- });
421
- }
422
-
423
- function updateContext(operationId, {
424
- expectedRevision,
425
- values = {},
426
- pendingSelection,
427
- } = {}) {
428
- if (!Number.isInteger(expectedRevision) || expectedRevision < 0) {
429
- throw new Error("runtime operation context revision 无效");
430
- }
431
- if (!values || typeof values !== "object" || Array.isArray(values)) {
432
- throw new Error("runtime operation context update 无效");
433
- }
434
- for (const field of Object.keys(values)) {
435
- if (!CONTEXT_FIELDS.has(field)) throw new Error(`runtime operation context 包含未知字段:${field}`);
436
- }
437
- return withLock(operationId, () => {
438
- const current = readUnlocked(operationId);
439
- if (!current || current.stage === "completed") throw new Error("runtime operation 不可更新");
440
- if (current.context_revision !== expectedRevision) {
441
- throw new Error("runtime operation context revision 已变化");
442
- }
443
- const nextContext = clone(current.context);
444
- for (const [field, value] of Object.entries(values)) {
445
- const normalized = field === "created_services"
446
- ? validateContext({ ...nextContext, created_services: value }).created_services
447
- : normalizeIdentifier(value, `context ${field}`);
448
- if (nextContext[field] !== null && field !== "created_services"
449
- && normalized !== nextContext[field]) {
450
- throw new Error(`runtime operation context ${field} 已经锁定`);
451
- }
452
- nextContext[field] = normalized;
453
- }
454
- return writeUnlocked({
455
- ...current,
456
- context: nextContext,
457
- context_revision: current.context_revision + 1,
458
- pending_selection: pendingSelection === undefined
459
- ? current.pending_selection
460
- : pendingSelection,
461
- updated_at: now(),
462
- });
463
- });
464
- }
465
-
466
- function recordFailure(operationId, { step, reason } = {}) {
467
- if (!FAILURE_CATEGORIES.has(reason)) throw new Error("runtime failure reason 无效");
468
- return withLock(operationId, () => {
469
- const current = readUnlocked(operationId);
470
- if (!current || current.stage === "completed") throw new Error("runtime operation 不可更新");
471
- if (!INTENT_DEFINITIONS[current.intent.type].steps.includes(step)) {
472
- throw new Error("runtime failure step 无效");
473
- }
474
- return writeUnlocked({
475
- ...current,
476
- failed_step: step,
477
- retry_budget: reason === "credential-expired" ? 1 : 0,
478
- last_failure_category: reason,
479
- updated_at: now(),
480
- });
481
- });
482
- }
483
-
484
- function consumeRetry(operationId) {
485
- return withLock(operationId, () => {
486
- const current = readUnlocked(operationId);
487
- if (!current) throw new Error("runtime operation 不存在");
488
- if (current.last_failure_category === "permission-denied") {
489
- throw new Error("当前操作权限不足,不能自动重试");
490
- }
491
- if (current.last_failure_category !== "credential-expired" || current.retry_budget !== 1) {
492
- throw new Error("runtime credential retry budget 已用尽");
493
- }
494
- return writeUnlocked({
495
- ...current,
496
- retry_count: current.retry_count + 1,
497
- retry_budget: 0,
498
- updated_at: now(),
499
- });
500
- });
501
- }
502
-
503
- function complete(operationId) {
504
- return withLock(operationId, () => {
505
- const current = readUnlocked(operationId);
506
- if (!current || current.environment_id === null) throw new Error("runtime operation 不能完成");
507
- return writeUnlocked({ ...current, stage: "completed", updated_at: now() });
508
- });
509
- }
510
-
511
- function list() {
512
- if (!fs.existsSync(directory)) return [];
513
- stateStore.ensurePrivateDirectory(directory);
514
- return fs.readdirSync(directory, { withFileTypes: true })
515
- .filter((entry) => entry.isFile() && UUID_PATTERN.test(entry.name.replace(/\.json$/, "")))
516
- .map((entry) => read(entry.name.replace(/\.json$/, "")))
517
- .sort((left, right) => left.created_at.localeCompare(right.created_at));
518
- }
519
-
520
- function activeOperationIds(environmentId) {
521
- assertUuid(environmentId, "environment_id ");
522
- return list()
523
- .filter((operation) => (
524
- operation.environment_id === environmentId && ACTIVE_STAGES.has(operation.stage)
525
- ))
526
- .map((operation) => operation.operation_id);
527
- }
528
-
529
- return {
530
- activeOperationIds,
531
- begin,
532
- bindEnvironment,
533
- complete,
534
- consumeRetry,
535
- createPending,
536
- directory,
537
- list,
538
- pathFor,
539
- read,
540
- recordFailure,
541
- updateContext,
542
- updateTargets,
543
- };
544
- }
545
-
546
- function resolveTargetReference({
547
- registry,
548
- explicitEnvironmentName,
549
- explicitTeamName,
550
- bareTargetName,
551
- teamNames = [],
552
- } = {}) {
553
- if (!registry || typeof registry.read !== "function") throw new Error("缺少环境注册表");
554
- const defaultEnvironmentId = registry.read().default_environment_id;
555
- if (explicitEnvironmentName !== undefined) {
556
- const environment = registry.findByName(explicitEnvironmentName);
557
- return environment
558
- ? { kind: "environment", environment_id: environment.id }
559
- : { kind: "unknown-environment", environment_name: explicitEnvironmentName };
560
- }
561
- if (explicitTeamName !== undefined) {
562
- if (!defaultEnvironmentId) return { kind: "missing-environment" };
563
- return {
564
- kind: "team",
565
- environment_id: defaultEnvironmentId,
566
- team_name: normalizeIdentifier(explicitTeamName, "team name"),
567
- };
568
- }
569
- if (bareTargetName !== undefined) {
570
- const environment = registry.findByName(bareTargetName);
571
- const team = teamNames.find((name) => String(name).normalize("NFKC") === String(bareTargetName).normalize("NFKC"));
572
- if (environment && team) {
573
- return {
574
- kind: "ambiguous",
575
- environment_id: environment.id,
576
- default_environment_id: defaultEnvironmentId,
577
- team_name: team,
578
- };
579
- }
580
- if (environment) return { kind: "environment", environment_id: environment.id };
581
- if (team && defaultEnvironmentId) {
582
- return { kind: "team", environment_id: defaultEnvironmentId, team_name: team };
583
- }
584
- return { kind: "unknown-target", target_name: bareTargetName };
585
- }
586
- return defaultEnvironmentId
587
- ? { kind: "environment", environment_id: defaultEnvironmentId }
588
- : { kind: "missing-environment" };
589
- }
590
-
591
- module.exports = {
592
- ACTIVE_STAGES,
593
- FAILURE_CATEGORIES,
594
- OPERATION_SCHEMA,
595
- createRuntimeOperationStore,
596
- resolveTargetReference,
597
- };
@@ -1,9 +0,0 @@
1
- $token = $env:RAINSKILLS_RAINBOND_JWT
2
- $baseUrl = $env:RAINSKILLS_RAINBOND_URL
3
-
4
- if ([string]::IsNullOrWhiteSpace($token) -or [string]::IsNullOrWhiteSpace($baseUrl)) {
5
- throw "Rainbond environment values were not provided."
6
- }
7
-
8
- [Environment]::SetEnvironmentVariable("RAINBOND_JWT", $token, "User")
9
- [Environment]::SetEnvironmentVariable("RAINBOND_URL", $baseUrl, "User")
@@ -1,16 +0,0 @@
1
- $ErrorActionPreference = "Stop"
2
-
3
- $outputPath = $env:RAINSKILLS_CREDENTIAL_OUTPUT_PATH
4
- if ([string]::IsNullOrWhiteSpace($outputPath)) {
5
- throw "Credential output path was not provided."
6
- }
7
-
8
- $token = [Environment]::GetEnvironmentVariable("RAINBOND_JWT", "User")
9
- $origin = [Environment]::GetEnvironmentVariable("RAINBOND_URL", "User")
10
- if ([string]::IsNullOrWhiteSpace($token) -or [string]::IsNullOrWhiteSpace($origin)) {
11
- throw "Rainbond user environment is incomplete."
12
- }
13
-
14
- $payload = @{ token = $token; origin = $origin } | ConvertTo-Json -Compress
15
- $utf8WithoutBom = New-Object System.Text.UTF8Encoding($false)
16
- [IO.File]::WriteAllText($outputPath, $payload, $utf8WithoutBom)