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.
Files changed (113) hide show
  1. package/_release/product-identity.json +1 -1
  2. package/console/dist/server/config/pd-config-store.d.ts +1 -0
  3. package/console/dist/server/config/pd-config-store.js +28 -6
  4. package/console/dist/server/routes/config.js +7 -3
  5. package/console/dist/ui/i18n/en.json +1 -5
  6. package/console/dist/ui/i18n/zh-CN.json +1 -5
  7. package/console/dist/ui/pages/control-center/RuntimeProfileManager.js +32 -67
  8. package/console/dist/web/assets/app.js +19 -19
  9. package/core/dist/runtime-v2/adapter/index.d.ts +0 -2
  10. package/core/dist/runtime-v2/adapter/index.d.ts.map +1 -1
  11. package/core/dist/runtime-v2/adapter/index.js +0 -1
  12. package/core/dist/runtime-v2/adapter/index.js.map +1 -1
  13. package/core/dist/runtime-v2/adapter/output-schema-registry.d.ts +3 -3
  14. package/core/dist/runtime-v2/adapter/pi-ai-runtime-adapter.d.ts.map +1 -1
  15. package/core/dist/runtime-v2/adapter/pi-ai-runtime-adapter.js +1 -2
  16. package/core/dist/runtime-v2/adapter/pi-ai-runtime-adapter.js.map +1 -1
  17. package/core/dist/runtime-v2/cli/probe.d.ts +4 -15
  18. package/core/dist/runtime-v2/cli/probe.d.ts.map +1 -1
  19. package/core/dist/runtime-v2/cli/probe.js +24 -44
  20. package/core/dist/runtime-v2/cli/probe.js.map +1 -1
  21. package/core/dist/runtime-v2/config/index.d.ts +1 -1
  22. package/core/dist/runtime-v2/config/index.d.ts.map +1 -1
  23. package/core/dist/runtime-v2/config/index.js.map +1 -1
  24. package/core/dist/runtime-v2/config/pd-config-agent-binding.d.ts +10 -17
  25. package/core/dist/runtime-v2/config/pd-config-agent-binding.d.ts.map +1 -1
  26. package/core/dist/runtime-v2/config/pd-config-agent-binding.js +23 -27
  27. package/core/dist/runtime-v2/config/pd-config-agent-binding.js.map +1 -1
  28. package/core/dist/runtime-v2/config/pd-config-defaults.d.ts +3 -5
  29. package/core/dist/runtime-v2/config/pd-config-defaults.d.ts.map +1 -1
  30. package/core/dist/runtime-v2/config/pd-config-defaults.js +17 -20
  31. package/core/dist/runtime-v2/config/pd-config-defaults.js.map +1 -1
  32. package/core/dist/runtime-v2/config/pd-config-effective.d.ts.map +1 -1
  33. package/core/dist/runtime-v2/config/pd-config-effective.js +4 -1
  34. package/core/dist/runtime-v2/config/pd-config-effective.js.map +1 -1
  35. package/core/dist/runtime-v2/config/pd-config-redaction.d.ts.map +1 -1
  36. package/core/dist/runtime-v2/config/pd-config-redaction.js +4 -7
  37. package/core/dist/runtime-v2/config/pd-config-redaction.js.map +1 -1
  38. package/core/dist/runtime-v2/config/pd-config-types.d.ts +5 -1
  39. package/core/dist/runtime-v2/config/pd-config-types.d.ts.map +1 -1
  40. package/core/dist/runtime-v2/config/pd-config-types.js +6 -0
  41. package/core/dist/runtime-v2/config/pd-config-types.js.map +1 -1
  42. package/core/dist/runtime-v2/config/pd-config-validate.d.ts.map +1 -1
  43. package/core/dist/runtime-v2/config/pd-config-validate.js +6 -0
  44. package/core/dist/runtime-v2/config/pd-config-validate.js.map +1 -1
  45. package/core/dist/runtime-v2/index.d.ts +1 -3
  46. package/core/dist/runtime-v2/index.d.ts.map +1 -1
  47. package/core/dist/runtime-v2/index.js +0 -2
  48. package/core/dist/runtime-v2/index.js.map +1 -1
  49. package/core/dist/runtime-v2/pain-signal-runtime-factory.d.ts +9 -7
  50. package/core/dist/runtime-v2/pain-signal-runtime-factory.d.ts.map +1 -1
  51. package/core/dist/runtime-v2/pain-signal-runtime-factory.js +59 -121
  52. package/core/dist/runtime-v2/pain-signal-runtime-factory.js.map +1 -1
  53. package/core/dist/runtime-v2/runtime-protocol.d.ts +2 -3
  54. package/core/dist/runtime-v2/runtime-protocol.d.ts.map +1 -1
  55. package/core/dist/runtime-v2/runtime-protocol.js +15 -10
  56. package/core/dist/runtime-v2/runtime-protocol.js.map +1 -1
  57. package/core/dist/workflow-funnel-loader.d.ts +0 -2
  58. package/core/dist/workflow-funnel-loader.d.ts.map +1 -1
  59. package/core/dist/workflow-funnel-loader.js.map +1 -1
  60. package/core/package.json +1 -1
  61. package/dist/mvp-config.d.ts.map +1 -1
  62. package/dist/mvp-config.js +8 -10
  63. package/dist/mvp-config.js.map +1 -1
  64. package/host-runtime/dist/internalization-consumer-cycle.js +4 -7
  65. package/host-runtime/package.json +1 -1
  66. package/package.json +2 -2
  67. package/pd-cli/dist/commands/diagnose.d.ts +0 -3
  68. package/pd-cli/dist/commands/diagnose.d.ts.map +1 -1
  69. package/pd-cli/dist/commands/diagnose.js +20 -57
  70. package/pd-cli/dist/commands/diagnose.js.map +1 -1
  71. package/pd-cli/dist/commands/pain-retry.d.ts +0 -3
  72. package/pd-cli/dist/commands/pain-retry.d.ts.map +1 -1
  73. package/pd-cli/dist/commands/pain-retry.js +11 -39
  74. package/pd-cli/dist/commands/pain-retry.js.map +1 -1
  75. package/pd-cli/dist/commands/runtime-internalization-run-once.d.ts.map +1 -1
  76. package/pd-cli/dist/commands/runtime-internalization-run-once.js +4 -2
  77. package/pd-cli/dist/commands/runtime-internalization-run-once.js.map +1 -1
  78. package/pd-cli/dist/commands/runtime.d.ts +1 -4
  79. package/pd-cli/dist/commands/runtime.d.ts.map +1 -1
  80. package/pd-cli/dist/commands/runtime.js +25 -95
  81. package/pd-cli/dist/commands/runtime.js.map +1 -1
  82. package/pd-cli/dist/index.js +2 -5
  83. package/pd-cli/dist/index.js.map +1 -1
  84. package/pd-cli/dist/services/config-doctor.d.ts.map +1 -1
  85. package/pd-cli/dist/services/config-doctor.js +9 -21
  86. package/pd-cli/dist/services/config-doctor.js.map +1 -1
  87. package/pd-cli/dist/services/mainline-snapshot-assembler.d.ts.map +1 -1
  88. package/pd-cli/dist/services/mainline-snapshot-assembler.js +2 -2
  89. package/pd-cli/dist/services/mainline-snapshot-assembler.js.map +1 -1
  90. package/pd-cli/dist/services/resolve-runtime-from-pd-config.d.ts +0 -7
  91. package/pd-cli/dist/services/resolve-runtime-from-pd-config.d.ts.map +1 -1
  92. package/pd-cli/dist/services/resolve-runtime-from-pd-config.js +0 -5
  93. package/pd-cli/dist/services/resolve-runtime-from-pd-config.js.map +1 -1
  94. package/pd-cli/dist/services/runtime-adapter-resolver.d.ts +1 -8
  95. package/pd-cli/dist/services/runtime-adapter-resolver.d.ts.map +1 -1
  96. package/pd-cli/dist/services/runtime-adapter-resolver.js +13 -39
  97. package/pd-cli/dist/services/runtime-adapter-resolver.js.map +1 -1
  98. package/plugin/dist/bundle.js +415 -418
  99. package/plugin/dist/openclaw.plugin.json +1 -1
  100. package/plugin/openclaw.plugin.json +1 -1
  101. package/plugin/package.json +1 -1
  102. package/release-manager/dist/mvp-config.d.ts.map +1 -1
  103. package/release-manager/dist/mvp-config.js +8 -10
  104. package/release-manager/dist/mvp-config.js.map +1 -1
  105. package/release-manager/package.json +2 -2
  106. package/core/dist/runtime-v2/adapter/openclaw-cli-runtime-adapter.d.ts +0 -72
  107. package/core/dist/runtime-v2/adapter/openclaw-cli-runtime-adapter.d.ts.map +0 -1
  108. package/core/dist/runtime-v2/adapter/openclaw-cli-runtime-adapter.js +0 -837
  109. package/core/dist/runtime-v2/adapter/openclaw-cli-runtime-adapter.js.map +0 -1
  110. package/core/dist/runtime-v2/utils/cli-process-runner.d.ts +0 -35
  111. package/core/dist/runtime-v2/utils/cli-process-runner.d.ts.map +0 -1
  112. package/core/dist/runtime-v2/utils/cli-process-runner.js +0 -263
  113. package/core/dist/runtime-v2/utils/cli-process-runner.js.map +0 -1
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
3
  "productVersion": "2.3.13",
4
- "sourceCommit": "8699502b4558837c908be45d3b71190335645a54"
4
+ "sourceCommit": "7fa8fd8361962f41676275ba26ac81d51e6ee84b"
5
5
  }
@@ -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 type change (type change = delete + create)
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
- // 6. Merge patch into existing profile, then extract only known fields
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
- // 7. Read raw config to preserve unknown sections, update the profile
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
- // 8. Validate the full updated config
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
- // 9. Atomic write
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
- // 10. Return the validated updated profile
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
- sendError(res, result.statusCode, result.error, result.message);
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
- sendError(res, result.statusCode, result.error, result.message);
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
- sendError(res, result.statusCode, result.error, result.message);
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
- "fieldSource": "Source (optional)",
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
- "fieldSource": "Source(可选)",
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 { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
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
- * Only includes fields relevant to the chosen type; omits empty optionals.
33
+ * Always pi-ai (ADR-0029); empty optional fields are omitted.
36
34
  */
37
35
  function buildCreateProfile(form) {
38
- const profile = { type: form.type };
39
- if (form.type === "pi-ai") {
40
- profile.provider = form.provider.trim();
41
- profile.model = form.model.trim();
42
- profile.apiKeyEnv = form.apiKeyEnv.trim();
43
- if (form.baseUrl.trim() !== "") {
44
- profile.baseUrl = form.baseUrl.trim();
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 `type` (server allows same-type no-op, rejects type change) plus all
60
- * non-empty type-relevant fields. Empty optionals are omitted so existing
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 = { type: form.type };
65
- if (form.type === "pi-ai") {
66
- if (form.provider.trim() !== "")
67
- patch.provider = form.provider.trim();
68
- if (form.model.trim() !== "")
69
- patch.model = form.model.trim();
70
- if (form.apiKeyEnv.trim() !== "")
71
- patch.apiKeyEnv = form.apiKeyEnv.trim();
72
- if (form.baseUrl.trim() !== "")
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.type === "pi-ai") {
133
- if (form.provider.trim() === "") {
134
- return t("pages.controlCenter.profiles.validationProviderRequired");
135
- }
136
- if (form.model.trim() === "") {
137
- return t("pages.controlCenter.profiles.validationModelRequired");
138
- }
139
- if (form.apiKeyEnv.trim() === "") {
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.fieldType") }), _jsxs("select", { id: "rpf-type", value: form.type, onChange: (e) => {
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" }))] }), _jsx("span", { className: "font-mono text-[11.5px] text-ink-3", children: p.type }), _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: [_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: () => {
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" ||