create-principles-disciple 1.145.25 → 1.145.26
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/_release/product-identity.json +1 -1
- package/console/dist/server/config/pd-config-store.d.ts +1 -0
- package/console/dist/server/config/pd-config-store.js +28 -6
- package/console/dist/server/routes/config.js +7 -3
- package/console/dist/ui/i18n/en.json +1 -5
- package/console/dist/ui/i18n/zh-CN.json +1 -5
- package/console/dist/ui/pages/control-center/RuntimeProfileManager.js +32 -67
- package/console/dist/web/assets/app.js +19 -19
- package/core/dist/runtime-v2/adapter/index.d.ts +0 -2
- package/core/dist/runtime-v2/adapter/index.d.ts.map +1 -1
- package/core/dist/runtime-v2/adapter/index.js +0 -1
- package/core/dist/runtime-v2/adapter/index.js.map +1 -1
- package/core/dist/runtime-v2/adapter/output-schema-registry.d.ts +3 -3
- package/core/dist/runtime-v2/adapter/pi-ai-runtime-adapter.d.ts.map +1 -1
- package/core/dist/runtime-v2/adapter/pi-ai-runtime-adapter.js +1 -2
- package/core/dist/runtime-v2/adapter/pi-ai-runtime-adapter.js.map +1 -1
- package/core/dist/runtime-v2/cli/probe.d.ts +4 -15
- package/core/dist/runtime-v2/cli/probe.d.ts.map +1 -1
- package/core/dist/runtime-v2/cli/probe.js +24 -44
- package/core/dist/runtime-v2/cli/probe.js.map +1 -1
- package/core/dist/runtime-v2/config/index.d.ts +1 -1
- package/core/dist/runtime-v2/config/index.d.ts.map +1 -1
- package/core/dist/runtime-v2/config/index.js.map +1 -1
- package/core/dist/runtime-v2/config/pd-config-agent-binding.d.ts +10 -17
- package/core/dist/runtime-v2/config/pd-config-agent-binding.d.ts.map +1 -1
- package/core/dist/runtime-v2/config/pd-config-agent-binding.js +23 -27
- package/core/dist/runtime-v2/config/pd-config-agent-binding.js.map +1 -1
- package/core/dist/runtime-v2/config/pd-config-defaults.d.ts +3 -5
- package/core/dist/runtime-v2/config/pd-config-defaults.d.ts.map +1 -1
- package/core/dist/runtime-v2/config/pd-config-defaults.js +17 -20
- package/core/dist/runtime-v2/config/pd-config-defaults.js.map +1 -1
- package/core/dist/runtime-v2/config/pd-config-effective.d.ts.map +1 -1
- package/core/dist/runtime-v2/config/pd-config-effective.js +4 -1
- package/core/dist/runtime-v2/config/pd-config-effective.js.map +1 -1
- package/core/dist/runtime-v2/config/pd-config-redaction.d.ts.map +1 -1
- package/core/dist/runtime-v2/config/pd-config-redaction.js +4 -7
- package/core/dist/runtime-v2/config/pd-config-redaction.js.map +1 -1
- package/core/dist/runtime-v2/config/pd-config-types.d.ts +5 -1
- package/core/dist/runtime-v2/config/pd-config-types.d.ts.map +1 -1
- package/core/dist/runtime-v2/config/pd-config-types.js +6 -0
- package/core/dist/runtime-v2/config/pd-config-types.js.map +1 -1
- package/core/dist/runtime-v2/config/pd-config-validate.d.ts.map +1 -1
- package/core/dist/runtime-v2/config/pd-config-validate.js +6 -0
- package/core/dist/runtime-v2/config/pd-config-validate.js.map +1 -1
- package/core/dist/runtime-v2/index.d.ts +1 -3
- package/core/dist/runtime-v2/index.d.ts.map +1 -1
- package/core/dist/runtime-v2/index.js +0 -2
- package/core/dist/runtime-v2/index.js.map +1 -1
- package/core/dist/runtime-v2/pain-signal-runtime-factory.d.ts +9 -7
- package/core/dist/runtime-v2/pain-signal-runtime-factory.d.ts.map +1 -1
- package/core/dist/runtime-v2/pain-signal-runtime-factory.js +59 -121
- package/core/dist/runtime-v2/pain-signal-runtime-factory.js.map +1 -1
- package/core/dist/runtime-v2/runtime-protocol.d.ts +2 -3
- package/core/dist/runtime-v2/runtime-protocol.d.ts.map +1 -1
- package/core/dist/runtime-v2/runtime-protocol.js +15 -10
- package/core/dist/runtime-v2/runtime-protocol.js.map +1 -1
- package/core/dist/workflow-funnel-loader.d.ts +0 -2
- package/core/dist/workflow-funnel-loader.d.ts.map +1 -1
- package/core/dist/workflow-funnel-loader.js.map +1 -1
- package/core/package.json +1 -1
- package/dist/mvp-config.d.ts.map +1 -1
- package/dist/mvp-config.js +8 -10
- package/dist/mvp-config.js.map +1 -1
- package/host-runtime/dist/internalization-consumer-cycle.js +4 -7
- package/host-runtime/package.json +1 -1
- package/package.json +2 -2
- package/pd-cli/dist/commands/diagnose.d.ts +0 -3
- package/pd-cli/dist/commands/diagnose.d.ts.map +1 -1
- package/pd-cli/dist/commands/diagnose.js +20 -57
- package/pd-cli/dist/commands/diagnose.js.map +1 -1
- package/pd-cli/dist/commands/pain-retry.d.ts +0 -3
- package/pd-cli/dist/commands/pain-retry.d.ts.map +1 -1
- package/pd-cli/dist/commands/pain-retry.js +11 -39
- package/pd-cli/dist/commands/pain-retry.js.map +1 -1
- package/pd-cli/dist/commands/runtime-internalization-run-once.d.ts.map +1 -1
- package/pd-cli/dist/commands/runtime-internalization-run-once.js +4 -2
- package/pd-cli/dist/commands/runtime-internalization-run-once.js.map +1 -1
- package/pd-cli/dist/commands/runtime.d.ts +1 -4
- package/pd-cli/dist/commands/runtime.d.ts.map +1 -1
- package/pd-cli/dist/commands/runtime.js +25 -95
- package/pd-cli/dist/commands/runtime.js.map +1 -1
- package/pd-cli/dist/index.js +2 -5
- package/pd-cli/dist/index.js.map +1 -1
- package/pd-cli/dist/services/config-doctor.d.ts.map +1 -1
- package/pd-cli/dist/services/config-doctor.js +9 -21
- package/pd-cli/dist/services/config-doctor.js.map +1 -1
- package/pd-cli/dist/services/mainline-snapshot-assembler.d.ts.map +1 -1
- package/pd-cli/dist/services/mainline-snapshot-assembler.js +2 -2
- package/pd-cli/dist/services/mainline-snapshot-assembler.js.map +1 -1
- package/pd-cli/dist/services/resolve-runtime-from-pd-config.d.ts +0 -7
- package/pd-cli/dist/services/resolve-runtime-from-pd-config.d.ts.map +1 -1
- package/pd-cli/dist/services/resolve-runtime-from-pd-config.js +0 -5
- package/pd-cli/dist/services/resolve-runtime-from-pd-config.js.map +1 -1
- package/pd-cli/dist/services/runtime-adapter-resolver.d.ts +1 -8
- package/pd-cli/dist/services/runtime-adapter-resolver.d.ts.map +1 -1
- package/pd-cli/dist/services/runtime-adapter-resolver.js +13 -39
- package/pd-cli/dist/services/runtime-adapter-resolver.js.map +1 -1
- package/plugin/dist/bundle.js +415 -418
- package/plugin/dist/openclaw.plugin.json +1 -1
- package/plugin/openclaw.plugin.json +1 -1
- package/plugin/package.json +1 -1
- package/release-manager/dist/mvp-config.d.ts.map +1 -1
- package/release-manager/dist/mvp-config.js +8 -10
- package/release-manager/dist/mvp-config.js.map +1 -1
- package/release-manager/package.json +2 -2
- package/core/dist/runtime-v2/adapter/openclaw-cli-runtime-adapter.d.ts +0 -72
- package/core/dist/runtime-v2/adapter/openclaw-cli-runtime-adapter.d.ts.map +0 -1
- package/core/dist/runtime-v2/adapter/openclaw-cli-runtime-adapter.js +0 -837
- package/core/dist/runtime-v2/adapter/openclaw-cli-runtime-adapter.js.map +0 -1
- package/core/dist/runtime-v2/utils/cli-process-runner.d.ts +0 -35
- package/core/dist/runtime-v2/utils/cli-process-runner.d.ts.map +0 -1
- package/core/dist/runtime-v2/utils/cli-process-runner.js +0 -263
- package/core/dist/runtime-v2/utils/cli-process-runner.js.map +0 -1
|
@@ -247,6 +247,7 @@ export declare function createRuntimeProfile(workspaceDir: string, profileId: st
|
|
|
247
247
|
* Update an existing runtime profile in .pd/config.yaml.
|
|
248
248
|
*
|
|
249
249
|
* - Rejects non-existent profile (404 not_found)
|
|
250
|
+
* - Rejects retired legacy profiles (400 retired_profile_type — read-only per ADR-0029)
|
|
250
251
|
* - Rejects type changes (400 bad_request — type change = delete + create)
|
|
251
252
|
* - Merges patch into existing profile, only known fields are persisted
|
|
252
253
|
* - Persists atomically, preserving unknown config sections
|
|
@@ -1083,6 +1083,17 @@ export function createRuntimeProfile(workspaceDir, profileId, payload) {
|
|
|
1083
1083
|
if (!structResult.ok) {
|
|
1084
1084
|
return { ok: false, statusCode: 400, error: structResult.error, message: structResult.message };
|
|
1085
1085
|
}
|
|
1086
|
+
// ADR-0029: the 'openclaw' profile type is read-only legacy. Existing legacy
|
|
1087
|
+
// profiles keep parsing and stay listed, but PD must never write a new one.
|
|
1088
|
+
if (structResult.type === 'openclaw') {
|
|
1089
|
+
return {
|
|
1090
|
+
ok: false,
|
|
1091
|
+
statusCode: 400,
|
|
1092
|
+
error: 'retired_profile_type',
|
|
1093
|
+
message: `Runtime profile type 'openclaw' is retired (ADR-0029) and cannot be created.`,
|
|
1094
|
+
nextAction: 'Create a pi-ai profile instead (provider + model + apiKeyEnv).',
|
|
1095
|
+
};
|
|
1096
|
+
}
|
|
1086
1097
|
// 3. Load existing config — refuse to write on malformed (rc-9)
|
|
1087
1098
|
const loadResult = loadPdConfig(workspaceDir);
|
|
1088
1099
|
if (!loadResult.ok) {
|
|
@@ -1151,6 +1162,7 @@ export function createRuntimeProfile(workspaceDir, profileId, payload) {
|
|
|
1151
1162
|
* Update an existing runtime profile in .pd/config.yaml.
|
|
1152
1163
|
*
|
|
1153
1164
|
* - Rejects non-existent profile (404 not_found)
|
|
1165
|
+
* - Rejects retired legacy profiles (400 retired_profile_type — read-only per ADR-0029)
|
|
1154
1166
|
* - Rejects type changes (400 bad_request — type change = delete + create)
|
|
1155
1167
|
* - Merges patch into existing profile, only known fields are persisted
|
|
1156
1168
|
* - Persists atomically, preserving unknown config sections
|
|
@@ -1194,7 +1206,17 @@ export function updateRuntimeProfile(workspaceDir, profileId, patch) {
|
|
|
1194
1206
|
message: `Profile '${profileId}' existence check passed but value is undefined.`,
|
|
1195
1207
|
nextAction: 'This is a bug in PD config resolution. Please report it.' };
|
|
1196
1208
|
}
|
|
1197
|
-
// 5. Reject
|
|
1209
|
+
// 5. Reject retired legacy profiles — ADR-0029: accepted on read, never written by PD
|
|
1210
|
+
if (existingProfile.type === 'openclaw') {
|
|
1211
|
+
return {
|
|
1212
|
+
ok: false,
|
|
1213
|
+
statusCode: 400,
|
|
1214
|
+
error: 'retired_profile_type',
|
|
1215
|
+
message: `Runtime profile type 'openclaw' is retired (ADR-0029) and cannot be updated. The profile stays readable for legacy compatibility only.`,
|
|
1216
|
+
nextAction: `DELETE /api/v1/config/profiles/${encodeURIComponent(profileId)} and create a pi-ai profile instead (provider + model + apiKeyEnv)`,
|
|
1217
|
+
};
|
|
1218
|
+
}
|
|
1219
|
+
// 6. Reject type change (type change = delete + create)
|
|
1198
1220
|
if (Object.hasOwn(patch, 'type')) {
|
|
1199
1221
|
const patchType = patch.type;
|
|
1200
1222
|
if (typeof patchType !== 'string' || patchType !== existingProfile.type) {
|
|
@@ -1207,10 +1229,10 @@ export function updateRuntimeProfile(workspaceDir, profileId, patch) {
|
|
|
1207
1229
|
};
|
|
1208
1230
|
}
|
|
1209
1231
|
}
|
|
1210
|
-
//
|
|
1232
|
+
// 7. Merge patch into existing profile, then extract only known fields
|
|
1211
1233
|
const mergedSource = { ...existingProfile, ...patch };
|
|
1212
1234
|
const mergedRecord = extractProfileFields(mergedSource, existingProfile.type);
|
|
1213
|
-
//
|
|
1235
|
+
// 8. Read raw config to preserve unknown sections, update the profile
|
|
1214
1236
|
const configPath = getPdConfigPath(workspaceDir);
|
|
1215
1237
|
const rawConfig = readRawConfig(configPath);
|
|
1216
1238
|
const profilesMap = isRecord(rawConfig.runtimeProfiles)
|
|
@@ -1218,7 +1240,7 @@ export function updateRuntimeProfile(workspaceDir, profileId, patch) {
|
|
|
1218
1240
|
: { ...effective.config.runtimeProfiles };
|
|
1219
1241
|
profilesMap[profileId] = mergedRecord;
|
|
1220
1242
|
rawConfig.runtimeProfiles = profilesMap;
|
|
1221
|
-
//
|
|
1243
|
+
// 9. Validate the full updated config
|
|
1222
1244
|
const validation = validatePdConfig(rawConfig);
|
|
1223
1245
|
if (!validation.ok) {
|
|
1224
1246
|
return {
|
|
@@ -1229,7 +1251,7 @@ export function updateRuntimeProfile(workspaceDir, profileId, patch) {
|
|
|
1229
1251
|
nextAction: 'Fix profile fields and retry',
|
|
1230
1252
|
};
|
|
1231
1253
|
}
|
|
1232
|
-
//
|
|
1254
|
+
// 10. Atomic write
|
|
1233
1255
|
try {
|
|
1234
1256
|
writeConfigAtomic(configPath, rawConfig);
|
|
1235
1257
|
}
|
|
@@ -1237,7 +1259,7 @@ export function updateRuntimeProfile(workspaceDir, profileId, patch) {
|
|
|
1237
1259
|
const message = err instanceof Error ? err.message : String(err);
|
|
1238
1260
|
return { ok: false, statusCode: 500, error: 'write_error', message: `Failed to write config: ${message}`, nextAction: 'Check disk space and file permissions for .pd/config.yaml' };
|
|
1239
1261
|
}
|
|
1240
|
-
//
|
|
1262
|
+
// 11. Return the validated updated profile
|
|
1241
1263
|
// Defensive guard: Object.hasOwn() doesn't narrow TS type.
|
|
1242
1264
|
const updatedProfile = validation.value.runtimeProfiles[profileId];
|
|
1243
1265
|
if (!updatedProfile) {
|
|
@@ -53,6 +53,10 @@ function safeParseBody(text) {
|
|
|
53
53
|
function isObject(value) {
|
|
54
54
|
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
55
55
|
}
|
|
56
|
+
/** Runtime-profile CRUD errors carry an operator next action — never drop it (rc-9). */
|
|
57
|
+
function sendProfileCrudError(res, result) {
|
|
58
|
+
sendError(res, result.statusCode, result.error, result.message, result.nextAction ? { nextAction: result.nextAction } : undefined);
|
|
59
|
+
}
|
|
56
60
|
// ── Route Handler ────────────────────────────────────────────────────────────
|
|
57
61
|
export async function handleConfigRoute(req, res, ctx) {
|
|
58
62
|
const { workspaceDir, subPath } = ctx;
|
|
@@ -301,7 +305,7 @@ export async function handleConfigRoute(req, res, ctx) {
|
|
|
301
305
|
}
|
|
302
306
|
const result = createRuntimeProfile(workspaceDir, body.id, body.profile);
|
|
303
307
|
if (!result.ok) {
|
|
304
|
-
|
|
308
|
+
sendProfileCrudError(res, result);
|
|
305
309
|
return;
|
|
306
310
|
}
|
|
307
311
|
// 201 Created for new resource
|
|
@@ -335,7 +339,7 @@ export async function handleConfigRoute(req, res, ctx) {
|
|
|
335
339
|
}
|
|
336
340
|
const result = updateRuntimeProfile(workspaceDir, profileId, body);
|
|
337
341
|
if (!result.ok) {
|
|
338
|
-
|
|
342
|
+
sendProfileCrudError(res, result);
|
|
339
343
|
return;
|
|
340
344
|
}
|
|
341
345
|
sendSuccess(res, { profileId: result.profileId, profile: result.profile });
|
|
@@ -344,7 +348,7 @@ export async function handleConfigRoute(req, res, ctx) {
|
|
|
344
348
|
if (method === 'DELETE') {
|
|
345
349
|
const result = deleteRuntimeProfile(workspaceDir, profileId);
|
|
346
350
|
if (!result.ok) {
|
|
347
|
-
|
|
351
|
+
sendProfileCrudError(res, result);
|
|
348
352
|
return;
|
|
349
353
|
}
|
|
350
354
|
sendSuccess(res, { profileId: result.profileId, profile: result.profile });
|
|
@@ -1574,7 +1574,6 @@
|
|
|
1574
1574
|
"fieldId": "Profile ID",
|
|
1575
1575
|
"fieldIdHint": "Unique identifier, cannot be changed after creation (e.g. anthropic-cloud)",
|
|
1576
1576
|
"fieldIdPlaceholder": "my-profile",
|
|
1577
|
-
"fieldType": "Type",
|
|
1578
1577
|
"fieldProvider": "Provider",
|
|
1579
1578
|
"fieldProviderPlaceholder": "anthropic",
|
|
1580
1579
|
"fieldModel": "Model",
|
|
@@ -1584,10 +1583,7 @@
|
|
|
1584
1583
|
"fieldApiKeyEnvPlaceholder": "ANTHROPIC_API_KEY",
|
|
1585
1584
|
"fieldBaseUrl": "Base URL (optional)",
|
|
1586
1585
|
"fieldBaseUrlPlaceholder": "https://api.anthropic.com",
|
|
1587
|
-
"
|
|
1588
|
-
"fieldSourcePlaceholder": "default",
|
|
1589
|
-
"typeOpenclaw": "openclaw",
|
|
1590
|
-
"typePiAi": "pi-ai",
|
|
1586
|
+
"retiredBadge": "retired",
|
|
1591
1587
|
"validationIdRequired": "Profile ID is required",
|
|
1592
1588
|
"validationProviderRequired": "pi-ai profile requires provider",
|
|
1593
1589
|
"validationModelRequired": "pi-ai profile requires model",
|
|
@@ -1574,7 +1574,6 @@
|
|
|
1574
1574
|
"fieldId": "Profile ID",
|
|
1575
1575
|
"fieldIdHint": "唯一标识符,创建后不可修改(如 anthropic-cloud)",
|
|
1576
1576
|
"fieldIdPlaceholder": "my-profile",
|
|
1577
|
-
"fieldType": "类型",
|
|
1578
1577
|
"fieldProvider": "Provider",
|
|
1579
1578
|
"fieldProviderPlaceholder": "anthropic",
|
|
1580
1579
|
"fieldModel": "Model",
|
|
@@ -1584,10 +1583,7 @@
|
|
|
1584
1583
|
"fieldApiKeyEnvPlaceholder": "ANTHROPIC_API_KEY",
|
|
1585
1584
|
"fieldBaseUrl": "Base URL(可选)",
|
|
1586
1585
|
"fieldBaseUrlPlaceholder": "https://api.anthropic.com",
|
|
1587
|
-
"
|
|
1588
|
-
"fieldSourcePlaceholder": "default",
|
|
1589
|
-
"typeOpenclaw": "openclaw",
|
|
1590
|
-
"typePiAi": "pi-ai",
|
|
1586
|
+
"retiredBadge": "已退役",
|
|
1591
1587
|
"validationIdRequired": "Profile ID 不能为空",
|
|
1592
1588
|
"validationProviderRequired": "pi-ai profile 必须填写 provider",
|
|
1593
1589
|
"validationModelRequired": "pi-ai profile 必须填写 model",
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useState } from "react";
|
|
3
3
|
import { useTranslation } from "react-i18next";
|
|
4
4
|
import { toast } from "sonner";
|
|
@@ -7,12 +7,10 @@ import { enumLabel } from "../../utils/enum-labels.js";
|
|
|
7
7
|
import { createRuntimeProfile, updateRuntimeProfile, deleteRuntimeProfile, } from "../../api.js";
|
|
8
8
|
const EMPTY_FORM = {
|
|
9
9
|
id: "",
|
|
10
|
-
type: "openclaw",
|
|
11
10
|
provider: "",
|
|
12
11
|
model: "",
|
|
13
12
|
apiKeyEnv: "",
|
|
14
13
|
baseUrl: "",
|
|
15
|
-
source: "",
|
|
16
14
|
};
|
|
17
15
|
/** 状态点样式:与 AgentCard 一致 (ready=green, needs_setup/not_ready/unknown=amber, disabled=ink-4) */
|
|
18
16
|
function readinessDotClasses(readiness) {
|
|
@@ -32,69 +30,45 @@ function readinessDotClasses(readiness) {
|
|
|
32
30
|
}
|
|
33
31
|
/**
|
|
34
32
|
* Build the profile object for a create request.
|
|
35
|
-
*
|
|
33
|
+
* Always pi-ai (ADR-0029); empty optional fields are omitted.
|
|
36
34
|
*/
|
|
37
35
|
function buildCreateProfile(form) {
|
|
38
|
-
const profile = {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
}
|
|
47
|
-
else {
|
|
48
|
-
if (form.source.trim() !== "")
|
|
49
|
-
profile.source = form.source.trim();
|
|
50
|
-
if (form.provider.trim() !== "")
|
|
51
|
-
profile.provider = form.provider.trim();
|
|
52
|
-
if (form.model.trim() !== "")
|
|
53
|
-
profile.model = form.model.trim();
|
|
36
|
+
const profile = {
|
|
37
|
+
type: "pi-ai",
|
|
38
|
+
provider: form.provider.trim(),
|
|
39
|
+
model: form.model.trim(),
|
|
40
|
+
apiKeyEnv: form.apiKeyEnv.trim(),
|
|
41
|
+
};
|
|
42
|
+
if (form.baseUrl.trim() !== "") {
|
|
43
|
+
profile.baseUrl = form.baseUrl.trim();
|
|
54
44
|
}
|
|
55
45
|
return profile;
|
|
56
46
|
}
|
|
57
47
|
/**
|
|
58
48
|
* Build the patch object for an update request.
|
|
59
|
-
* Sends
|
|
60
|
-
*
|
|
61
|
-
* values are preserved (merge-patch semantics on the server).
|
|
49
|
+
* Sends only pi-ai fields. Empty optionals are omitted so existing values are
|
|
50
|
+
* preserved (merge-patch semantics on the server).
|
|
62
51
|
*/
|
|
63
52
|
function buildUpdatePatch(form) {
|
|
64
|
-
const patch = {
|
|
65
|
-
if (form.
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
patch.baseUrl = form.baseUrl.trim();
|
|
74
|
-
}
|
|
75
|
-
else {
|
|
76
|
-
if (form.source.trim() !== "")
|
|
77
|
-
patch.source = form.source.trim();
|
|
78
|
-
if (form.provider.trim() !== "")
|
|
79
|
-
patch.provider = form.provider.trim();
|
|
80
|
-
if (form.model.trim() !== "")
|
|
81
|
-
patch.model = form.model.trim();
|
|
82
|
-
}
|
|
53
|
+
const patch = {};
|
|
54
|
+
if (form.provider.trim() !== "")
|
|
55
|
+
patch.provider = form.provider.trim();
|
|
56
|
+
if (form.model.trim() !== "")
|
|
57
|
+
patch.model = form.model.trim();
|
|
58
|
+
if (form.apiKeyEnv.trim() !== "")
|
|
59
|
+
patch.apiKeyEnv = form.apiKeyEnv.trim();
|
|
60
|
+
if (form.baseUrl.trim() !== "")
|
|
61
|
+
patch.baseUrl = form.baseUrl.trim();
|
|
83
62
|
return patch;
|
|
84
63
|
}
|
|
85
|
-
/** Pre-fill form from an existing profile summary (edit mode). */
|
|
64
|
+
/** Pre-fill form from an existing pi-ai profile summary (edit mode). */
|
|
86
65
|
function formFromProfile(p) {
|
|
87
|
-
// type is validated to be a known ProfileType by the caller before invoking;
|
|
88
|
-
// here we guard defensively without `as`.
|
|
89
|
-
const type = p.type === "pi-ai" ? "pi-ai" : "openclaw";
|
|
90
66
|
return {
|
|
91
67
|
id: p.id,
|
|
92
|
-
type,
|
|
93
68
|
provider: p.provider ?? "",
|
|
94
69
|
model: p.model ?? "",
|
|
95
70
|
apiKeyEnv: p.apiKeyEnv ?? "",
|
|
96
71
|
baseUrl: "",
|
|
97
|
-
source: "",
|
|
98
72
|
};
|
|
99
73
|
}
|
|
100
74
|
export function RuntimeProfileManager({ profiles, defaultRuntimeId, onMutated, }) {
|
|
@@ -129,16 +103,14 @@ export function RuntimeProfileManager({ profiles, defaultRuntimeId, onMutated, }
|
|
|
129
103
|
if (mode === "create" && form.id.trim() === "") {
|
|
130
104
|
return t("pages.controlCenter.profiles.validationIdRequired");
|
|
131
105
|
}
|
|
132
|
-
if (form.
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
return t("pages.controlCenter.profiles.validationApiKeyEnvRequired");
|
|
141
|
-
}
|
|
106
|
+
if (form.provider.trim() === "") {
|
|
107
|
+
return t("pages.controlCenter.profiles.validationProviderRequired");
|
|
108
|
+
}
|
|
109
|
+
if (form.model.trim() === "") {
|
|
110
|
+
return t("pages.controlCenter.profiles.validationModelRequired");
|
|
111
|
+
}
|
|
112
|
+
if (form.apiKeyEnv.trim() === "") {
|
|
113
|
+
return t("pages.controlCenter.profiles.validationApiKeyEnvRequired");
|
|
142
114
|
}
|
|
143
115
|
return null;
|
|
144
116
|
}
|
|
@@ -206,21 +178,14 @@ export function RuntimeProfileManager({ profiles, defaultRuntimeId, onMutated, }
|
|
|
206
178
|
? t("pages.controlCenter.profiles.formTitleCreate")
|
|
207
179
|
: t("pages.controlCenter.profiles.formTitleEdit", {
|
|
208
180
|
id: form.id,
|
|
209
|
-
}) }), _jsx("button", { type: "button", onClick: closeForm, className: "text-[12px] text-ink-4 hover:text-ink-2 transition-colors", children: t("pages.controlCenter.profiles.cancelButton") })] }), _jsxs("div", { className: "grid grid-cols-1 sm:grid-cols-2 gap-x-[14px] gap-y-[12px]", children: [_jsxs("div", { children: [_jsx("label", { className: labelClass, htmlFor: "rpf-id", children: t("pages.controlCenter.profiles.fieldId") }), _jsx("input", { id: "rpf-id", type: "text", value: form.id, onChange: (e) => handleFieldChange("id", e.target.value), disabled: mode === "edit" || submitting, placeholder: t("pages.controlCenter.profiles.fieldIdPlaceholder"), className: inputClass, autoComplete: "off", spellCheck: false }), _jsx("p", { className: hintClass, children: t("pages.controlCenter.profiles.fieldIdHint") })] }), _jsxs("div", { children: [_jsx("label", { className: labelClass, htmlFor: "rpf-type", children: t("pages.controlCenter.profiles.
|
|
210
|
-
// rc-2: no `as` bypass — narrow via runtime check.
|
|
211
|
-
// The select only emits "openclaw" | "pi-ai", but we guard
|
|
212
|
-
// defensively so the value is provably ProfileType.
|
|
213
|
-
const v = e.target.value;
|
|
214
|
-
const typed = v === "pi-ai" ? "pi-ai" : "openclaw";
|
|
215
|
-
handleFieldChange("type", typed);
|
|
216
|
-
}, disabled: mode === "edit" || submitting, className: inputClass, children: [_jsx("option", { value: "openclaw", children: t("pages.controlCenter.profiles.typeOpenclaw") }), _jsx("option", { value: "pi-ai", children: t("pages.controlCenter.profiles.typePiAi") })] }), mode === "edit" && (_jsx("p", { className: hintClass, children: t("pages.controlCenter.profiles.fieldIdHint") }))] }), form.type === "pi-ai" && (_jsxs(_Fragment, { children: [_jsxs("div", { children: [_jsx("label", { className: labelClass, htmlFor: "rpf-provider", children: t("pages.controlCenter.profiles.fieldProvider") }), _jsx("input", { id: "rpf-provider", type: "text", value: form.provider, onChange: (e) => handleFieldChange("provider", e.target.value), disabled: submitting, placeholder: t("pages.controlCenter.profiles.fieldProviderPlaceholder"), className: inputClass, autoComplete: "off", spellCheck: false })] }), _jsxs("div", { children: [_jsx("label", { className: labelClass, htmlFor: "rpf-model", children: t("pages.controlCenter.profiles.fieldModel") }), _jsx("input", { id: "rpf-model", type: "text", value: form.model, onChange: (e) => handleFieldChange("model", e.target.value), disabled: submitting, placeholder: t("pages.controlCenter.profiles.fieldModelPlaceholder"), className: inputClass, autoComplete: "off", spellCheck: false })] }), _jsxs("div", { children: [_jsx("label", { className: labelClass, htmlFor: "rpf-apikeyenv", children: t("pages.controlCenter.profiles.fieldApiKeyEnv") }), _jsx("input", { id: "rpf-apikeyenv", type: "text", value: form.apiKeyEnv, onChange: (e) => handleFieldChange("apiKeyEnv", e.target.value), disabled: submitting, placeholder: t("pages.controlCenter.profiles.fieldApiKeyEnvPlaceholder"), className: cn(inputClass, "font-mono"), autoComplete: "off", spellCheck: false }), _jsx("p", { className: hintClass, children: t("pages.controlCenter.profiles.fieldApiKeyEnvHint") })] }), _jsxs("div", { children: [_jsx("label", { className: labelClass, htmlFor: "rpf-baseurl", children: t("pages.controlCenter.profiles.fieldBaseUrl") }), _jsx("input", { id: "rpf-baseurl", type: "text", value: form.baseUrl, onChange: (e) => handleFieldChange("baseUrl", e.target.value), disabled: submitting, placeholder: t("pages.controlCenter.profiles.fieldBaseUrlPlaceholder"), className: inputClass, autoComplete: "off", spellCheck: false })] })] })), form.type === "openclaw" && (_jsxs(_Fragment, { children: [_jsxs("div", { children: [_jsx("label", { className: labelClass, htmlFor: "rpf-source", children: t("pages.controlCenter.profiles.fieldSource") }), _jsx("input", { id: "rpf-source", type: "text", value: form.source, onChange: (e) => handleFieldChange("source", e.target.value), disabled: submitting, placeholder: t("pages.controlCenter.profiles.fieldSourcePlaceholder"), className: inputClass, autoComplete: "off", spellCheck: false })] }), _jsxs("div", { children: [_jsx("label", { className: labelClass, htmlFor: "rpf-provider-oc", children: t("pages.controlCenter.profiles.fieldProvider") }), _jsx("input", { id: "rpf-provider-oc", type: "text", value: form.provider, onChange: (e) => handleFieldChange("provider", e.target.value), disabled: submitting, placeholder: t("pages.controlCenter.profiles.fieldProviderPlaceholder"), className: inputClass, autoComplete: "off", spellCheck: false })] }), _jsxs("div", { children: [_jsx("label", { className: labelClass, htmlFor: "rpf-model-oc", children: t("pages.controlCenter.profiles.fieldModel") }), _jsx("input", { id: "rpf-model-oc", type: "text", value: form.model, onChange: (e) => handleFieldChange("model", e.target.value), disabled: submitting, placeholder: t("pages.controlCenter.profiles.fieldModelPlaceholder"), className: inputClass, autoComplete: "off", spellCheck: false })] })] }))] }), formError !== null && (_jsx("div", { className: "mt-3 px-[12px] py-[8px] border border-danger/35 rounded-[4px] bg-danger/10 text-[12px] text-danger font-mono", children: formError })), _jsxs("div", { className: "mt-3 flex items-center gap-[8px]", children: [_jsx("button", { type: "submit", disabled: submitting, className: "border border-gov bg-gov text-paper rounded-[3px] px-[14px] py-[6px] text-[12.5px] font-medium hover:bg-gov-2 transition-colors disabled:opacity-50 focus-visible:outline-2 focus-visible:outline-gov focus-visible:outline-offset-2", children: submitting
|
|
181
|
+
}) }), _jsx("button", { type: "button", onClick: closeForm, className: "text-[12px] text-ink-4 hover:text-ink-2 transition-colors", children: t("pages.controlCenter.profiles.cancelButton") })] }), _jsxs("div", { className: "grid grid-cols-1 sm:grid-cols-2 gap-x-[14px] gap-y-[12px]", children: [_jsxs("div", { children: [_jsx("label", { className: labelClass, htmlFor: "rpf-id", children: t("pages.controlCenter.profiles.fieldId") }), _jsx("input", { id: "rpf-id", type: "text", value: form.id, onChange: (e) => handleFieldChange("id", e.target.value), disabled: mode === "edit" || submitting, placeholder: t("pages.controlCenter.profiles.fieldIdPlaceholder"), className: inputClass, autoComplete: "off", spellCheck: false }), _jsx("p", { className: hintClass, children: t("pages.controlCenter.profiles.fieldIdHint") })] }), _jsxs("div", { children: [_jsx("label", { className: labelClass, htmlFor: "rpf-provider", children: t("pages.controlCenter.profiles.fieldProvider") }), _jsx("input", { id: "rpf-provider", type: "text", value: form.provider, onChange: (e) => handleFieldChange("provider", e.target.value), disabled: submitting, placeholder: t("pages.controlCenter.profiles.fieldProviderPlaceholder"), className: inputClass, autoComplete: "off", spellCheck: false })] }), _jsxs("div", { children: [_jsx("label", { className: labelClass, htmlFor: "rpf-model", children: t("pages.controlCenter.profiles.fieldModel") }), _jsx("input", { id: "rpf-model", type: "text", value: form.model, onChange: (e) => handleFieldChange("model", e.target.value), disabled: submitting, placeholder: t("pages.controlCenter.profiles.fieldModelPlaceholder"), className: inputClass, autoComplete: "off", spellCheck: false })] }), _jsxs("div", { children: [_jsx("label", { className: labelClass, htmlFor: "rpf-apikeyenv", children: t("pages.controlCenter.profiles.fieldApiKeyEnv") }), _jsx("input", { id: "rpf-apikeyenv", type: "text", value: form.apiKeyEnv, onChange: (e) => handleFieldChange("apiKeyEnv", e.target.value), disabled: submitting, placeholder: t("pages.controlCenter.profiles.fieldApiKeyEnvPlaceholder"), className: cn(inputClass, "font-mono"), autoComplete: "off", spellCheck: false }), _jsx("p", { className: hintClass, children: t("pages.controlCenter.profiles.fieldApiKeyEnvHint") })] }), _jsxs("div", { children: [_jsx("label", { className: labelClass, htmlFor: "rpf-baseurl", children: t("pages.controlCenter.profiles.fieldBaseUrl") }), _jsx("input", { id: "rpf-baseurl", type: "text", value: form.baseUrl, onChange: (e) => handleFieldChange("baseUrl", e.target.value), disabled: submitting, placeholder: t("pages.controlCenter.profiles.fieldBaseUrlPlaceholder"), className: inputClass, autoComplete: "off", spellCheck: false })] })] }), formError !== null && (_jsx("div", { className: "mt-3 px-[12px] py-[8px] border border-danger/35 rounded-[4px] bg-danger/10 text-[12px] text-danger font-mono", children: formError })), _jsxs("div", { className: "mt-3 flex items-center gap-[8px]", children: [_jsx("button", { type: "submit", disabled: submitting, className: "border border-gov bg-gov text-paper rounded-[3px] px-[14px] py-[6px] text-[12.5px] font-medium hover:bg-gov-2 transition-colors disabled:opacity-50 focus-visible:outline-2 focus-visible:outline-gov focus-visible:outline-offset-2", children: submitting
|
|
217
182
|
? mode === "create"
|
|
218
183
|
? t("pages.controlCenter.profiles.creating")
|
|
219
184
|
: t("pages.controlCenter.profiles.saving")
|
|
220
185
|
: t("pages.controlCenter.profiles.saveButton") }), _jsx("button", { type: "button", onClick: closeForm, disabled: submitting, className: "border border-line bg-surface text-ink-3 rounded-[3px] px-[14px] py-[6px] text-[12.5px] font-medium hover:border-line-2 hover:text-ink transition-colors disabled:opacity-50", children: t("pages.controlCenter.profiles.cancelButton") })] })] })), profiles.length === 0 ? (_jsx("div", { className: "bg-surface border border-line-2 rounded-[4px] px-[16px] py-[14px] text-[12.5px] text-ink-4 italic", children: t("pages.controlCenter.profiles.empty") })) : (_jsxs("div", { className: "bg-surface border border-line-2 rounded-[4px] overflow-hidden", children: [_jsxs("div", { className: "grid grid-cols-[12px_1fr_84px_1fr_1fr_1fr_auto] gap-[10px] items-center px-[16px] py-[9px] bg-paper-2 border-b border-line-2 font-mono text-[10.5px] uppercase tracking-[0.04em] text-ink-4", children: [_jsx("span", {}), _jsx("span", { children: t("pages.controlCenter.profiles.columnId") }), _jsx("span", { children: t("pages.controlCenter.profiles.columnType") }), _jsx("span", { children: t("pages.controlCenter.profiles.columnProvider") }), _jsx("span", { children: t("pages.controlCenter.profiles.columnModel") }), _jsx("span", { children: t("pages.controlCenter.profiles.columnApiKeyEnv") }), _jsx("span", { className: "text-right", children: t("pages.controlCenter.profiles.columnActions") })] }), profiles.map((p) => {
|
|
221
186
|
const isDefault = p.id === defaultRuntimeId;
|
|
222
187
|
const isDeleteTarget = deleteTarget === p.id;
|
|
223
|
-
return (_jsxs("div", { className: "border-b border-line-2 last:border-b-0", children: [_jsxs("div", { className: "grid grid-cols-[12px_1fr_84px_1fr_1fr_1fr_auto] gap-[10px] items-center px-[16px] py-[10px] text-[12.5px]", children: [_jsx("div", { className: readinessDotClasses(p.readiness), "aria-label": enumLabel("readiness", p.readiness, t), title: enumLabel("readiness", p.readiness, t) }), _jsxs("div", { className: "min-w-0 flex items-center gap-[6px]", children: [_jsx("span", { className: "font-mono text-[12px] text-ink truncate", children: p.id }), isDefault && (_jsx("span", { className: "shrink-0 text-[9.5px] font-mono px-[5px] py-[1px] rounded-[2px] bg-gov/10 text-gov border border-gov/22 tracking-[0.02em]", children: "default" }))] }),
|
|
188
|
+
return (_jsxs("div", { className: "border-b border-line-2 last:border-b-0", children: [_jsxs("div", { className: "grid grid-cols-[12px_1fr_84px_1fr_1fr_1fr_auto] gap-[10px] items-center px-[16px] py-[10px] text-[12.5px]", children: [_jsx("div", { className: readinessDotClasses(p.readiness), "aria-label": enumLabel("readiness", p.readiness, t), title: enumLabel("readiness", p.readiness, t) }), _jsxs("div", { className: "min-w-0 flex items-center gap-[6px]", children: [_jsx("span", { className: "font-mono text-[12px] text-ink truncate", children: p.id }), isDefault && (_jsx("span", { className: "shrink-0 text-[9.5px] font-mono px-[5px] py-[1px] rounded-[2px] bg-gov/10 text-gov border border-gov/22 tracking-[0.02em]", children: "default" }))] }), _jsxs("span", { className: "font-mono text-[11.5px] text-ink-3 flex items-center gap-[5px]", children: [p.type, p.type === "openclaw" && (_jsx("span", { className: "text-[9.5px] font-mono px-[5px] py-[1px] rounded-[2px] bg-amber/10 text-amber border border-amber/22 tracking-[0.02em]", children: t("pages.controlCenter.profiles.retiredBadge") }))] }), _jsx("span", { className: "text-ink-3 truncate", children: p.provider ?? "—" }), _jsx("span", { className: "text-ink-3 truncate", children: p.model ?? "—" }), _jsx("span", { className: "font-mono text-[11.5px] text-ink-3 truncate", children: p.apiKeyEnv ?? "—" }), _jsxs("div", { className: "flex items-center justify-end gap-[6px]", children: [p.type !== "openclaw" && (_jsx("button", { type: "button", onClick: () => openEdit(p), disabled: mode !== "closed" || deleting, className: "text-[11.5px] px-[10px] py-[4px] rounded-[3px] border border-line bg-surface text-ink-3 hover:border-line-2 hover:text-ink transition-colors disabled:opacity-40 disabled:cursor-not-allowed", children: t("pages.controlCenter.profiles.editButton") })), _jsx("button", { type: "button", onClick: () => {
|
|
224
189
|
setDeleteTarget(p.id);
|
|
225
190
|
setDeleteError(null);
|
|
226
191
|
}, disabled: mode !== "closed" ||
|