dsh-harbor-evolution 0.9.2 → 0.9.3
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/README.md +10 -9
- package/lib/client.js +203 -398
- package/lib/historical-web.js +2 -2
- package/lib/session-diagnostic.js +22 -7
- package/lib/session-materializer.js +42 -2
- package/lib/session-selection.js +115 -52
- package/package.json +1 -1
- package/schemas/historical-generation-batch.schema.json +23 -2
package/lib/client.js
CHANGED
|
@@ -44,6 +44,7 @@ __export(index_exports, {
|
|
|
44
44
|
clearStructuredHarborReferences: () => clearStructuredHarborReferences,
|
|
45
45
|
commitIssuedDraft: () => commitIssuedDraft,
|
|
46
46
|
comparisonCandidates: () => comparisonCandidates,
|
|
47
|
+
createHarborActionHandlers: () => createHarborActionHandlers,
|
|
47
48
|
dashboardFailureState: () => dashboardFailureState,
|
|
48
49
|
decodeToolResult: () => decodeToolResult,
|
|
49
50
|
effectiveHarborSubmissionReference: () => effectiveHarborSubmissionReference,
|
|
@@ -132,22 +133,10 @@ function jobAttention(job) {
|
|
|
132
133
|
}
|
|
133
134
|
|
|
134
135
|
// src/client/workbench-journey.js
|
|
135
|
-
function harborQuestionKeys(context) {
|
|
136
|
-
const focus = context?.selection?.at(-1);
|
|
137
|
-
if (focus?.kind === "evaluator-source") return ["askSource", "askSourceChange"];
|
|
138
|
-
if (focus?.kind === "trial-set") return ["askSelectedTrials", "suggestedQuestion3"];
|
|
139
|
-
if (focus?.kind === "metric") return ["askMetric", "suggestedQuestion3"];
|
|
140
|
-
if (focus?.kind === "hypothesis") return ["askHypothesis", "suggestedQuestion3"];
|
|
141
|
-
if (focus?.kind === "gate-reason") return ["askGateReason", "suggestedQuestion3"];
|
|
142
|
-
if (context?.object?.trial || focus?.trial) return ["suggestedQuestion1", "suggestedQuestion3", "askCandidateChange"];
|
|
143
|
-
if (context?.object?.job) return ["askHealth", "suggestedQuestion4"];
|
|
144
|
-
return ["askGettingStarted"];
|
|
145
|
-
}
|
|
146
|
-
function harborQuestionLabelKey(key) {
|
|
147
|
-
return ["askSource", "askSourceChange", "askSelectedTrials", "askMetric", "askHypothesis", "askGateReason", "askCandidateChange", "askHealth", "askGettingStarted"].includes(key) ? `${key}Label` : key;
|
|
148
|
-
}
|
|
149
136
|
var JOURNEY_MESSAGES = {
|
|
150
137
|
zh: {
|
|
138
|
+
preparedInHarbor: "\u5DF2\u51C6\u5907\u597D\uFF0C\u8BF7\u6253\u5F00 Harbor \u6807\u7B7E\u67E5\u770B\u3002",
|
|
139
|
+
navigationPending: "\u8BF7\u6253\u5F00 Harbor \u6807\u7B7E\u67E5\u770B\u5DF2\u8BF7\u6C42\u7684\u5BF9\u8C61\uFF1B\u82E5\u672A\u5B9A\u4F4D\uFF0C\u8BF7\u91CD\u65B0\u9009\u62E9\u5BF9\u8C61\u3002",
|
|
151
140
|
replyReady: "AI \u5DF2\u56DE\u590D \xB7 \u70B9 + \u67E5\u770B",
|
|
152
141
|
historyOnly: "\u5EF6\u7EED\u4F1A\u8BDD\u5386\u53F2\uFF0C\u672A\u91CD\u65B0\u8BFB\u53D6\u9875\u9762",
|
|
153
142
|
draftRecoveryReselect: "\u5DF2\u8FD4\u56DE\u539F\u5BF9\u8C61\u9875\u9762\u3002\u5176\u5185\u5BB9\u6216\u9009\u4E2D\u96C6\u5408\u5DF2\u53D8\u5316\uFF0C\u8BF7\u91CD\u65B0\u9009\u62E9\u5177\u4F53\u5185\u5BB9\u540E\u63D0\u95EE\uFF1B\u65E7\u5EFA\u8BAE\u548C\u7F16\u8F91\u5DF2\u4FDD\u7559\uFF0C\u4E0D\u4F1A\u81EA\u52A8\u6269\u5927\u8303\u56F4\u3002",
|
|
@@ -210,6 +199,8 @@ var JOURNEY_MESSAGES = {
|
|
|
210
199
|
repreparePrompt: "\u8BF7\u91CD\u65B0\u8BFB\u53D6\u8FD9\u4E2A\u5BF9\u8C61\u7684\u6700\u65B0\u8BC1\u636E\uFF0C\u66F4\u65B0\u4E4B\u524D\u7684\u4FEE\u6539\u5EFA\u8BAE\u5E76\u751F\u6210\u65B0\u7684\u8349\u7A3F\u4F9B\u6211\u5BA1\u9605\u3002\u4E0D\u8981\u5199\u5165\u6587\u4EF6\u3001\u8FD0\u884C\u8BC4\u6D4B\u6216\u53D1\u5E03\u3002\u4E4B\u524D\u7684\u5EFA\u8BAE\uFF08\u4EC5\u4F5C\u5F85\u6838\u5B9E\u53C2\u8003\uFF09\uFF1A"
|
|
211
200
|
},
|
|
212
201
|
en: {
|
|
202
|
+
preparedInHarbor: "Ready. Open the Harbor tab to view it.",
|
|
203
|
+
navigationPending: "Open the Harbor tab to inspect the requested object; select it again if it was not located.",
|
|
213
204
|
replyReady: "AI replied \xB7 expand to read",
|
|
214
205
|
historyOnly: "Conversation history; page not re-read",
|
|
215
206
|
draftRecoveryReselect: "Returned to the original object page. Its content or selection changed; explicitly select it again before asking. Suggestions and edits remain intact; scope is never expanded automatically.",
|
|
@@ -273,6 +264,111 @@ var JOURNEY_MESSAGES = {
|
|
|
273
264
|
}
|
|
274
265
|
};
|
|
275
266
|
|
|
267
|
+
// src/client/historical-launcher-state.js
|
|
268
|
+
var HISTORICAL_MESSAGES = {
|
|
269
|
+
zh: {
|
|
270
|
+
historicalLaunch: "\u8BC4\u6D4B\u6700\u8FD1\u4F1A\u8BDD",
|
|
271
|
+
historicalLaunchShort: "\u5F00\u59CB\u8BC4\u6D4B",
|
|
272
|
+
historicalLaunchHint: "\u6700\u591A 3 \u6761 \xB7 \u786E\u8BA4\u540E\u5F00\u59CB",
|
|
273
|
+
historicalLaunchBody: "\u81EA\u52A8\u67E5\u627E\u5F53\u524D DSH \u53EF\u8BBF\u95EE\u7684\u5386\u53F2\u4F1A\u8BDD\uFF0C\u770B\u770B\u5DF2\u5B8C\u6210\u7684\u4EFB\u52A1\u6709\u54EA\u4E9B\u53EF\u4EE5\u6539\u8FDB\u3002",
|
|
274
|
+
historicalPreparing: "\u6B63\u5728\u67E5\u627E\u6700\u8FD1\u53EF\u8BC4\u6D4B\u7684\u4F1A\u8BDD\u2026",
|
|
275
|
+
historicalPreparingShort: "\u8BFB\u53D6\u4E2D\u2026",
|
|
276
|
+
historicalPreviewTitle: "\u8BC4\u6D4B\u8FD9\u4E9B\u4F1A\u8BDD\uFF1F",
|
|
277
|
+
historicalPreviewHint: "\u5DF2\u81EA\u52A8\u67E5\u627E DSH \u5386\u53F2\u8BB0\u5F55\u3002\u786E\u8BA4\u524D\u53EA\u8BFB\u53D6\uFF0C\u4E0D\u542F\u52A8\u8BC4\u6D4B\u3002",
|
|
278
|
+
historicalPrivacyHint: "\u786E\u8BA4\u540E\uFF0C\u6240\u9009\u4F1A\u8BDD\u7684\u8131\u654F\u5BF9\u8BDD\u5C06\u53D1\u9001\u7ED9\u4E0B\u65B9\u8BC4\u5BA1\u6A21\u578B\uFF0C\u53EF\u80FD\u4EA7\u751F\u6A21\u578B\u8D39\u7528\uFF1B\u4E0D\u4F1A\u91CD\u65B0\u6267\u884C\u539F\u4EFB\u52A1\u3002",
|
|
279
|
+
historicalPartialHint: "\u672C\u6B21\u4ECE\u6700\u8FD1\u4E00\u6279\u8BB0\u5F55\u4E2D\u9009\u53D6\uFF0C\u672A\u904D\u5386\u5168\u90E8\u5386\u53F2\u3002",
|
|
280
|
+
historicalUnreadableHint: "\u90E8\u5206\u5386\u53F2\u8BB0\u5F55\u672A\u80FD\u8BFB\u53D6\uFF0C\u672A\u7EB3\u5165\u672C\u6B21\u8BC4\u6D4B\u3002",
|
|
281
|
+
historicalConfirm: "\u786E\u8BA4\u5E76\u5F00\u59CB\u8BC4\u6D4B",
|
|
282
|
+
historicalStarting: "\u6B63\u5728\u542F\u52A8\u8BC4\u6D4B\u2026",
|
|
283
|
+
historicalRunning: "\u6B63\u5728\u8BC4\u6D4B\u5386\u53F2\u4F1A\u8BDD",
|
|
284
|
+
historicalStartingHint: "\u6B63\u5728\u63D0\u4EA4\u5DF2\u786E\u8BA4\u7684\u8BC4\u6D4B\uFF0C\u8BF7\u7A0D\u5019\u3002\u5173\u95ED\u7A97\u53E3\u4E0D\u4F1A\u64A4\u56DE\u786E\u8BA4\u3002",
|
|
285
|
+
historicalErrorTitle: "\u8BC4\u6D4B\u6682\u65F6\u65E0\u6CD5\u7EE7\u7EED",
|
|
286
|
+
historicalErrorBody: "\u8BF7\u67E5\u770B\u4E0B\u65B9\u539F\u56E0\u3002\u91CD\u8BD5\u4F1A\u5148\u91CD\u65B0\u67E5\u627E\u4F1A\u8BDD\uFF0C\u4E0D\u4F1A\u76F4\u63A5\u91CD\u8DD1\u8BC4\u6D4B\u3002",
|
|
287
|
+
historicalErrorDetails: "\u6280\u672F\u8BE6\u60C5",
|
|
288
|
+
historicalRunningHint: "\u53EF\u4EE5\u5173\u95ED\u7A97\u53E3\u7EE7\u7EED\u5DE5\u4F5C\u3002\u8BC4\u6D4B\u5728\u540E\u53F0\u7EE7\u7EED\uFF0C\u5B8C\u6210\u540E\u6253\u5F00\u7ED3\u679C\u3002",
|
|
289
|
+
historicalActive: "\u67E5\u770B\u8BC4\u6D4B\u72B6\u6001",
|
|
290
|
+
historicalActiveShort: "\u67E5\u770B\u72B6\u6001",
|
|
291
|
+
historicalCompleted: "\u8BC4\u6D4B\u5B8C\u6210\uFF0C\u6B63\u5728\u6253\u5F00\u7ED3\u679C\u2026",
|
|
292
|
+
recentSessions: "\u672C\u6B21\u8BC4\u6D4B\u7684\u4F1A\u8BDD",
|
|
293
|
+
selectedSessions: "\u4F1A\u8BDD\u6570\u91CF",
|
|
294
|
+
historicalSessionUnit: "\u6761\u4F1A\u8BDD",
|
|
295
|
+
requestEstimate: "\u9884\u8BA1\u8BC4\u5BA1\u8BF7\u6C42",
|
|
296
|
+
tokenExpiry: "\u9884\u89C8\u6709\u6548\u671F",
|
|
297
|
+
generatorRole: "\u751F\u6210\u5668",
|
|
298
|
+
generatorRoleValue: "\u4EA7\u751F\u8FD9\u4E9B\u4F1A\u8BDD\u7684 DSH Agent",
|
|
299
|
+
evaluatorIdentity: "\u8BC4\u6D4B\u5668\u8EAB\u4EFD",
|
|
300
|
+
judgeIdentity: "\u8BC4\u5BA1\u6A21\u578B",
|
|
301
|
+
coupling: "\u6A21\u578B\u8026\u5408",
|
|
302
|
+
evidenceRetention: "\u8BC1\u636E\u4FDD\u7559",
|
|
303
|
+
historicalBoundaries: "\u8BC4\u6D4B\u8BF4\u660E",
|
|
304
|
+
historicalBoundaryDetail: "\u53EA\u8BCA\u65AD\u5DF2\u6709\u5BF9\u8BDD\uFF0C\u4E0D\u91CD\u8DD1\u539F\u4EFB\u52A1\uFF0C\u4E0D\u81EA\u52A8\u4FEE\u6539\u3001\u90E8\u7F72\u6216\u664B\u7EA7 Agent\uFF1B\u7ED3\u679C\u4E0D\u4EE3\u8868\u8BC4\u6D4B\u5668\u672C\u8EAB\u5DF2\u7ECF\u9A8C\u8BC1\u53EF\u9760\u3002",
|
|
305
|
+
feedbackCounts: "\u53CD\u9988",
|
|
306
|
+
turnCounts: "\u8F6E\u6B21",
|
|
307
|
+
toolCounts: "\u5DE5\u5177\u8C03\u7528",
|
|
308
|
+
previewAgain: "\u91CD\u65B0\u67E5\u627E",
|
|
309
|
+
noEligibleHint: "\u5F53\u524D DSH \u53EF\u8BBF\u95EE\u7684\u5386\u53F2\u8BB0\u5F55\u4E2D\uFF0C\u6682\u672A\u627E\u5230\u5DF2\u5B8C\u6210\u4E14\u53EF\u8BC4\u6D4B\u7684\u4F1A\u8BDD\u3002\u53EF\u4EE5\u7A0D\u540E\u91CD\u8BD5\u3002",
|
|
310
|
+
historyReadFailedHint: "\u90E8\u5206\u5386\u53F2\u4F1A\u8BDD\u672A\u80FD\u8BFB\u53D6\uFF0C\u6682\u65F6\u65E0\u6CD5\u51C6\u5907\u8BC4\u6D4B\u3002\u8BF7\u91CD\u8BD5\uFF1B\u8FD9\u4E0D\u8868\u793A\u5386\u53F2\u8BB0\u5F55\u4E0D\u5B58\u5728\u3002",
|
|
311
|
+
historyWindowExhaustedHint: "\u672C\u6B21\u5DF2\u68C0\u67E5\u7684\u6700\u8FD1\u8BB0\u5F55\u4E2D\uFF0C\u6682\u672A\u627E\u5230\u53EF\u8BC4\u6D4B\u4F1A\u8BDD\u3002\u66F4\u65E9\u7684\u8BB0\u5F55\u5C1A\u672A\u68C0\u67E5\uFF0C\u53EF\u4EE5\u7A0D\u540E\u91CD\u8BD5\u3002",
|
|
312
|
+
changedSessionHint: "\u4F1A\u8BDD\u6216\u8BC4\u6D4B\u8BBE\u7F6E\u5DF2\u53D8\u5316\uFF0C\u6216\u9884\u89C8\u5DF2\u8FC7\u671F\u3002\u8BF7\u91CD\u65B0\u67E5\u627E\u5E76\u786E\u8BA4\u3002",
|
|
313
|
+
historicalGenericError: "\u672C\u6B21\u64CD\u4F5C\u672A\u5B8C\u6210\u3002\u8BF7\u91CD\u8BD5\uFF1B\u5982\u4ECD\u5931\u8D25\uFF0C\u8BF7\u4FDD\u7559\u9519\u8BEF\u4FE1\u606F\u4EE5\u4FBF\u6392\u67E5\u3002",
|
|
314
|
+
cancel: "\u53D6\u6D88"
|
|
315
|
+
},
|
|
316
|
+
en: {
|
|
317
|
+
historicalLaunch: "Evaluate recent Sessions",
|
|
318
|
+
historicalLaunchShort: "Start evaluation",
|
|
319
|
+
historicalLaunchHint: "Up to 3 \xB7 confirm before starting",
|
|
320
|
+
historicalLaunchBody: "Automatically find history available to this DSH and see how completed tasks could improve.",
|
|
321
|
+
historicalPreparing: "Finding recent Sessions to evaluate\u2026",
|
|
322
|
+
historicalPreparingShort: "Loading\u2026",
|
|
323
|
+
historicalPreviewTitle: "Evaluate these Sessions?",
|
|
324
|
+
historicalPreviewHint: "DSH history was found automatically. Nothing is evaluated until you confirm.",
|
|
325
|
+
historicalPrivacyHint: "After confirmation, redacted conversations from the selected Sessions will be sent to the review model below and may incur model charges. The original tasks will not rerun.",
|
|
326
|
+
historicalPartialHint: "This sample comes from a recent set of records, not a full scan of all history.",
|
|
327
|
+
historicalUnreadableHint: "Some historical records could not be read and are not included in this evaluation.",
|
|
328
|
+
historicalConfirm: "Confirm and start evaluation",
|
|
329
|
+
historicalStarting: "Starting evaluation\u2026",
|
|
330
|
+
historicalRunning: "Evaluating historical Sessions",
|
|
331
|
+
historicalStartingHint: "Submitting the evaluation you confirmed. Closing this window will not withdraw that confirmation.",
|
|
332
|
+
historicalErrorTitle: "Evaluation could not continue",
|
|
333
|
+
historicalErrorBody: "Review the reason below. Retrying finds Sessions again; it does not rerun an evaluation without confirmation.",
|
|
334
|
+
historicalErrorDetails: "Technical details",
|
|
335
|
+
historicalRunningHint: "You can close this window and keep working. Evaluation continues in the background and opens the results when complete.",
|
|
336
|
+
historicalActive: "View evaluation status",
|
|
337
|
+
historicalActiveShort: "View status",
|
|
338
|
+
historicalCompleted: "Evaluation complete. Opening results\u2026",
|
|
339
|
+
recentSessions: "Sessions to evaluate",
|
|
340
|
+
selectedSessions: "Session count",
|
|
341
|
+
historicalSessionUnit: "Sessions",
|
|
342
|
+
requestEstimate: "Estimated review requests",
|
|
343
|
+
tokenExpiry: "Preview expires",
|
|
344
|
+
generatorRole: "Generator",
|
|
345
|
+
generatorRoleValue: "The DSH Agent that produced these Sessions",
|
|
346
|
+
evaluatorIdentity: "Evaluator identity",
|
|
347
|
+
judgeIdentity: "Review model",
|
|
348
|
+
coupling: "Model coupling",
|
|
349
|
+
evidenceRetention: "Evidence retention",
|
|
350
|
+
historicalBoundaries: "About this evaluation",
|
|
351
|
+
historicalBoundaryDetail: "Diagnoses existing conversations only. No task rerun, automatic Agent changes, deployment, or promotion. These results do not establish evaluator reliability.",
|
|
352
|
+
feedbackCounts: "Feedback",
|
|
353
|
+
turnCounts: "Turns",
|
|
354
|
+
toolCounts: "Tool calls",
|
|
355
|
+
previewAgain: "Find Sessions again",
|
|
356
|
+
noEligibleHint: "No completed, eligible Sessions were found in the history currently available to this DSH. Try again later.",
|
|
357
|
+
historyReadFailedHint: "Some historical Sessions could not be read, so evaluation cannot be prepared yet. Retry; this does not mean the history is missing.",
|
|
358
|
+
historyWindowExhaustedHint: "No eligible Sessions were found among the recent records checked in this attempt. Older records have not been checked. Try again later.",
|
|
359
|
+
changedSessionHint: "The Sessions or evaluation settings changed, or the preview expired. Find Sessions again and confirm the new preview.",
|
|
360
|
+
historicalGenericError: "This operation did not complete. Retry; if it keeps failing, retain the error details for troubleshooting.",
|
|
361
|
+
cancel: "Cancel"
|
|
362
|
+
}
|
|
363
|
+
};
|
|
364
|
+
function historicalErrorHint(code, t) {
|
|
365
|
+
if (code === "NO_ELIGIBLE_SESSIONS") return t("noEligibleHint");
|
|
366
|
+
if (code === "SESSION_HISTORY_READ_FAILED") return t("historyReadFailedHint");
|
|
367
|
+
if (code === "SESSION_HISTORY_WINDOW_EXHAUSTED" || code === "SESSION_SELECTION_TOO_EXPENSIVE") return t("historyWindowExhaustedHint");
|
|
368
|
+
if (/SESSION_(?:SAMPLE|FEEDBACK)_CHANGED|WORKSPACE_MISMATCH|TOKEN_(?:INVALID|EXPIRED)|PREVIEW_(?:INVALID|WORKSPACE_MISMATCH)/.test(code)) return t("changedSessionHint");
|
|
369
|
+
return t("historicalGenericError");
|
|
370
|
+
}
|
|
371
|
+
|
|
276
372
|
// src/client/action-draft-card.jsx
|
|
277
373
|
var import_react = __toESM(require("react"), 1);
|
|
278
374
|
|
|
@@ -435,7 +531,7 @@ var ACTION_CARD_MESSAGES = {
|
|
|
435
531
|
zh: {
|
|
436
532
|
actionStateRecovered: "\u5DF2\u6838\u67E5\u5E76\u89E3\u9501\uFF1B\u672A\u91CD\u8BD5",
|
|
437
533
|
actionRecoveryReleased: "\u8BCA\u65AD\u9501\u5DF2\u89E3\u9664\u3002\u539F\u8FD0\u884C\u72B6\u6001\u548C\u8BC1\u636E\u4FDD\u7559\uFF0C\u6CA1\u6709\u81EA\u52A8\u91CD\u8BD5\u3002",
|
|
438
|
-
actionRecoveryTaskCenter: "\u6253\u5F00\
|
|
534
|
+
actionRecoveryTaskCenter: "\u6253\u5F00 Harbor \u6807\u7B7E\u4E2D\u7684\u300C\u540E\u53F0\u4EFB\u52A1\u300D\uFF0C\u6838\u67E5\u8FDB\u7A0B\u4E0E\u8D44\u6E90\u540E\u53EF\u786E\u8BA4\u89E3\u9501\u3002",
|
|
439
535
|
actionDiagnosticPartialView: "\u67E5\u770B\u8FD0\u884C\uFF0F\u90E8\u5206\u8BC1\u636E",
|
|
440
536
|
actionSuggestion: "AI \u5EFA\u8BAE",
|
|
441
537
|
actionReviewSource: "\u5BA1\u9605\u5E76\u4FEE\u6539",
|
|
@@ -552,7 +648,7 @@ var ACTION_CARD_MESSAGES = {
|
|
|
552
648
|
en: {
|
|
553
649
|
actionStateRecovered: "Inspected and unlocked; not retried",
|
|
554
650
|
actionRecoveryReleased: "Diagnostic lock released. Original status and evidence retained; no automatic retry.",
|
|
555
|
-
actionRecoveryTaskCenter: "Open Background tasks
|
|
651
|
+
actionRecoveryTaskCenter: "Open Background tasks in the Harbor tab to inspect the process and resources before confirming unlock.",
|
|
556
652
|
actionDiagnosticPartialView: "View run / partial evidence",
|
|
557
653
|
actionSuggestion: "AI suggestion",
|
|
558
654
|
actionReviewSource: "Review and edit",
|
|
@@ -987,7 +1083,7 @@ var OPERATION_TRAY_MESSAGES = {
|
|
|
987
1083
|
}
|
|
988
1084
|
};
|
|
989
1085
|
for (const locale of ["zh", "en"]) Object.assign(OPERATION_TRAY_MESSAGES[locale], Object.fromEntries(Object.entries(PHASES[locale]).map(([key, value]) => [`phase_${key}`, value])));
|
|
990
|
-
function OperationTray({ sessionId, scopeKey, request, update, onViewResult, t }) {
|
|
1086
|
+
function OperationTray({ sessionId, scopeKey, request, update, onViewResult, t, hideWhenEmpty = false }) {
|
|
991
1087
|
const label = (key) => t?.(key) ?? OPERATION_TRAY_MESSAGES.zh[key] ?? key;
|
|
992
1088
|
const ownerKey = `${sessionId}
|
|
993
1089
|
${scopeKey ?? ""}`;
|
|
@@ -1015,6 +1111,7 @@ ${scopeKey ?? ""}`;
|
|
|
1015
1111
|
}, [sessionId, scopeKey, request, attempt, limit]);
|
|
1016
1112
|
const active = state.items.filter(actionOperationActive).length;
|
|
1017
1113
|
const attention = state.items.filter(operationNeedsRecovery).length;
|
|
1114
|
+
if (hideWhenEmpty && !state.loading && !state.error && state.items.length === 0) return null;
|
|
1018
1115
|
return /* @__PURE__ */ import_react2.default.createElement("section", { className: "hse-operation-tray", "aria-label": label("tasks") }, /* @__PURE__ */ import_react2.default.createElement("button", { type: "button", className: "hse-operation-toggle", "aria-expanded": expanded, onClick: () => setExpanded((value) => !value) }, label("tasks"), " \xB7 ", /* @__PURE__ */ import_react2.default.createElement("span", { role: "status" }, state.loading ? label("loading") : `${active} ${label("active")} \xB7 ${attention} ${label("attention")} \xB7 ${state.items.length} ${label("records")}`), expanded ? " \u2212" : " +"), state.error ? /* @__PURE__ */ import_react2.default.createElement("p", { role: "alert" }, label("stale"), /* @__PURE__ */ import_react2.default.createElement("button", { type: "button", onClick: () => setAttempt((value) => value + 1) }, label("refresh"))) : null, expanded ? /* @__PURE__ */ import_react2.default.createElement("div", { className: "hse-operation-list" }, /* @__PURE__ */ import_react2.default.createElement("p", null, label("taskHint")), !state.loading && !state.items.length && !state.error ? /* @__PURE__ */ import_react2.default.createElement("p", null, label("empty")) : null, state.items.map((operation) => /* @__PURE__ */ import_react2.default.createElement(OperationItem, { key: `${ownerKey}:${operation.operationId}`, ...{ operation, request, update, onViewResult, label }, stale: Boolean(state.error), onChanged: () => setAttempt((value) => value + 1) })), state.nextCursor && limit < 100 ? /* @__PURE__ */ import_react2.default.createElement("button", { type: "button", onClick: () => setLimit((value) => Math.min(100, value + 20)) }, label("loadMore")) : state.truncated || state.nextCursor ? /* @__PURE__ */ import_react2.default.createElement("p", null, label("more")) : null) : null);
|
|
1019
1116
|
}
|
|
1020
1117
|
function OperationItem({ operation, request, update, onViewResult, onChanged, label, stale }) {
|
|
@@ -1079,78 +1176,6 @@ function OperationItem({ operation, request, update, onViewResult, onChanged, la
|
|
|
1079
1176
|
}) }, label(operation.status === "CANCELLING" || pending === "cancel" ? "CANCELLING" : "cancel")) : null, needsRecovery ? /* @__PURE__ */ import_react2.default.createElement("button", { type: "button", disabled: stale || Boolean(pending), onClick: () => void inspect() }, label(pending === "inspect" ? "checking" : "inspect")) : null), needsRecovery ? /* @__PURE__ */ import_react2.default.createElement("p", null, label("inspectHint")) : null, inspection ? /* @__PURE__ */ import_react2.default.createElement("section", { className: "hse-operation-inspection" }, /* @__PURE__ */ import_react2.default.createElement("p", null, label(inspection.canRecover ? "releaseReview" : "blocked")), /* @__PURE__ */ import_react2.default.createElement("p", null, label("process"), ": ", label(inspection.process?.state ?? "unknown"), " \xB7 ", label("resources"), ": ", label(inspection.resources?.state ?? "unknown")), inspection.process?.pid ? /* @__PURE__ */ import_react2.default.createElement("code", null, "PID ", inspection.process.pid, " \xB7 PGID ", inspection.process.groupId ?? "\u2014") : null, (inspection.resources?.items ?? []).map((resource) => /* @__PURE__ */ import_react2.default.createElement("p", { key: `${resource.kind}:${resource.id}` }, /* @__PURE__ */ import_react2.default.createElement("code", null, resource.kind, " \xB7 ", resource.id, /* @__PURE__ */ import_react2.default.createElement("br", null), "Compose: ", resource.project))), (inspection.blockers ?? []).map((check, index) => /* @__PURE__ */ import_react2.default.createElement("p", { key: index }, check.message ?? check.code)), inspection.canRecover ? /* @__PURE__ */ import_react2.default.createElement(import_react2.default.Fragment, null, /* @__PURE__ */ import_react2.default.createElement("label", null, /* @__PURE__ */ import_react2.default.createElement("input", { type: "checkbox", checked: reviewed, onChange: (event) => setReviewed(event.target.checked) }), label("releaseReview")), /* @__PURE__ */ import_react2.default.createElement("button", { type: "button", disabled: stale || !reviewed || Boolean(pending), onClick: () => void release() }, label(pending === "release" ? "saving" : "release"))) : null) : null, error ? /* @__PURE__ */ import_react2.default.createElement("p", { role: "alert" }, String(error?.message ?? error)) : null, /* @__PURE__ */ import_react2.default.createElement("details", null, /* @__PURE__ */ import_react2.default.createElement("summary", null, label("detail")), /* @__PURE__ */ import_react2.default.createElement("code", null, operation.operationId), /* @__PURE__ */ import_react2.default.createElement("p", null, operation.createdAt)));
|
|
1080
1177
|
}
|
|
1081
1178
|
|
|
1082
|
-
// src/client/conversation-projection.js
|
|
1083
|
-
var HUMAN_KINDS = /* @__PURE__ */ new Set(["user", "steering"]);
|
|
1084
|
-
var HISTORY_LIMIT = 24;
|
|
1085
|
-
function humanText(node) {
|
|
1086
|
-
if (!HUMAN_KINDS.has(node?.kind) || !Array.isArray(node.content)) return "";
|
|
1087
|
-
return node.content.filter((part) => part?.type === "text" && typeof part.text === "string").map((part) => part.text).join("\n");
|
|
1088
|
-
}
|
|
1089
|
-
function humanReference(node) {
|
|
1090
|
-
const tokens = [];
|
|
1091
|
-
const question = humanText(node).replace(/<harbor-context-ref\b([^<>]*)>[\s\S]*?<\/harbor-context-ref\s*>/g, (reference, attributes) => {
|
|
1092
|
-
const match = attributes.match(/(?:^|\s)context-snapshot-id\s*=\s*(?:"([^"]*)"|'([^']*)')/);
|
|
1093
|
-
const token = match?.[1] ?? match?.[2];
|
|
1094
|
-
if (!/^hctx_[A-Za-z0-9_-]+$/.test(token ?? "")) return reference;
|
|
1095
|
-
tokens.push(token);
|
|
1096
|
-
return "";
|
|
1097
|
-
}).trim();
|
|
1098
|
-
return { tokens, question };
|
|
1099
|
-
}
|
|
1100
|
-
function emptyProjection() {
|
|
1101
|
-
return { nodes: [], originNodes: [], active: false, anchorSeq: void 0, turn: void 0, question: "", continuation: false, turns: [], selectedSeq: void 0, contextToken: void 0 };
|
|
1102
|
-
}
|
|
1103
|
-
function humanSegments(nodes) {
|
|
1104
|
-
const segments = [];
|
|
1105
|
-
let anchor;
|
|
1106
|
-
let previous;
|
|
1107
|
-
for (let index = 0; index < nodes.length; index += 1) {
|
|
1108
|
-
const node = nodes[index];
|
|
1109
|
-
if (!HUMAN_KINDS.has(node?.kind) || !Number.isFinite(node.seq)) continue;
|
|
1110
|
-
if (previous) previous.endIndex = index;
|
|
1111
|
-
const reference = humanReference(node);
|
|
1112
|
-
const attached = reference.tokens.length > 0 && reference.tokens.every((value) => value === reference.tokens[0]);
|
|
1113
|
-
if (attached) anchor = { index, seq: node.seq, contextToken: reference.tokens[0] };
|
|
1114
|
-
else if (reference.tokens.length) anchor = void 0;
|
|
1115
|
-
if (!anchor) {
|
|
1116
|
-
previous = void 0;
|
|
1117
|
-
continue;
|
|
1118
|
-
}
|
|
1119
|
-
const segment = { index, endIndex: nodes.length, seq: node.seq, question: reference.question, contextAttached: attached, contextToken: anchor.contextToken, anchor };
|
|
1120
|
-
segments.push(segment);
|
|
1121
|
-
previous = segment;
|
|
1122
|
-
}
|
|
1123
|
-
return segments;
|
|
1124
|
-
}
|
|
1125
|
-
function segmentNodes(nodes, segment) {
|
|
1126
|
-
const candidates = nodes.slice(segment.index + 1, segment.endIndex).filter((node) => !Number.isFinite(node?.seq) || node.seq > segment.seq);
|
|
1127
|
-
const turn = candidates.find((node) => node?.kind === "assistant" && Number.isFinite(node.turn))?.turn;
|
|
1128
|
-
return { nodes: candidates.filter((node) => turn === void 0 || !Number.isFinite(node?.turn) || node.turn === turn), turn };
|
|
1129
|
-
}
|
|
1130
|
-
function harborConversationProjection(nodes, token, selectedSeq) {
|
|
1131
|
-
if (!Array.isArray(nodes) || !/^hctx_[A-Za-z0-9_-]+$/.test(token ?? "")) return emptyProjection();
|
|
1132
|
-
const requestedSeq = typeof selectedSeq === "object" && selectedSeq !== null ? selectedSeq.selectedSeq : selectedSeq;
|
|
1133
|
-
const segments = humanSegments(nodes);
|
|
1134
|
-
const history = segments.slice(-HISTORY_LIMIT);
|
|
1135
|
-
const latestForToken = history.findLast((segment) => segment.contextToken === token);
|
|
1136
|
-
if (!latestForToken) return emptyProjection();
|
|
1137
|
-
const selected = history.find((segment) => segment.seq === requestedSeq) ?? latestForToken;
|
|
1138
|
-
const projected = segmentNodes(nodes, selected);
|
|
1139
|
-
const origin = segments.find((segment) => segment.index === selected.anchor.index);
|
|
1140
|
-
return {
|
|
1141
|
-
nodes: projected.nodes,
|
|
1142
|
-
originNodes: origin ? segmentNodes(nodes, origin).nodes : [],
|
|
1143
|
-
active: selected === latestForToken && selected.endIndex === nodes.length && selected.contextToken === token,
|
|
1144
|
-
anchorSeq: selected.anchor.seq,
|
|
1145
|
-
turn: projected.turn,
|
|
1146
|
-
question: selected.question,
|
|
1147
|
-
continuation: !selected.contextAttached,
|
|
1148
|
-
turns: history.map(({ seq, question, contextAttached, contextToken }) => ({ seq, question, contextAttached, contextToken })),
|
|
1149
|
-
selectedSeq: selected.seq,
|
|
1150
|
-
contextToken: selected.contextToken
|
|
1151
|
-
};
|
|
1152
|
-
}
|
|
1153
|
-
|
|
1154
1179
|
// src/client/evaluator-editor.jsx
|
|
1155
1180
|
var import_react3 = __toESM(require("react"), 1);
|
|
1156
1181
|
|
|
@@ -1740,7 +1765,7 @@ var dictionaries = {
|
|
|
1740
1765
|
jobsHint: "\u70B9\u51FB Job \u540E\uFF0C\u6700\u591A\u518D\u70B9\u4E00\u6B21\u5373\u53EF\u8FDB\u5165\u5BF9\u5E94 Trial \u7684\u8BC1\u636E\u3002",
|
|
1741
1766
|
workspace: "\u5DE5\u4F5C\u7A7A\u95F4",
|
|
1742
1767
|
workspaceSelect: "\u9009\u62E9 Harbor \u5DE5\u4F5C\u7A7A\u95F4",
|
|
1743
|
-
empty: "\u8FD8\u6CA1\u6709
|
|
1768
|
+
empty: "\u8FD8\u6CA1\u6709\u8BC4\u6D4B\u7ED3\u679C\u3002\u53EF\u4EE5\u5148\u8BD5\u8BD5\u300C\u8BC4\u6D4B\u6700\u8FD1\u4F1A\u8BDD\u300D\uFF0C\u81EA\u52A8\u67E5\u627E\u5F53\u524D DSH \u7684\u8FD1\u671F\u771F\u5B9E\u4F1A\u8BDD\uFF0C\u786E\u8BA4\u540E\u5F00\u59CB\u3002",
|
|
1744
1769
|
askAi: "Ask AI",
|
|
1745
1770
|
askAboutThis: "\u5F15\u7528\u540E\u63D0\u95EE",
|
|
1746
1771
|
currentPage: "\u5F53\u524D\u9875\u9762",
|
|
@@ -1801,43 +1826,7 @@ var dictionaries = {
|
|
|
1801
1826
|
errorNextPermission: "\u68C0\u67E5\u5F53\u524D Session \u7684\u5DE5\u4F5C\u7A7A\u95F4\u4E0E\u8BBF\u95EE\u6743\u9650\u3002",
|
|
1802
1827
|
errorNextMissing: "\u5237\u65B0\u5217\u8868\u5E76\u786E\u8BA4\u5BF9\u8C61\u4ECD\u7136\u5B58\u5728\u3002",
|
|
1803
1828
|
errorNextArtifact: "\u68C0\u67E5 Job \u7684 Artifact / Audit\uFF0C\u4FEE\u590D\u4EA7\u7269\u540E\u91CD\u8BD5\u3002",
|
|
1804
|
-
|
|
1805
|
-
historicalLaunchShort: "\u5F00\u59CB\u8BC4\u6D4B",
|
|
1806
|
-
historicalLaunchHint: "\u6700\u591A 10 \u6761 \xB7 \u5148\u9884\u89C8\u518D\u8FD0\u884C",
|
|
1807
|
-
historicalLaunchBody: "\u7528\u5F53\u524D DSH Agent \u5DF2\u5B8C\u6210\u7684\u771F\u5B9E\u4EFB\u52A1\u505A\u8BCA\u65AD\uFF0C\u4E0D\u91CD\u65B0\u8FD0\u884C Candidate\u3002",
|
|
1808
|
-
historicalPreparing: "\u6B63\u5728\u67E5\u627E\u53EF\u8BC4\u6D4B\u4F1A\u8BDD\u2026",
|
|
1809
|
-
historicalPreparingShort: "\u8BFB\u53D6\u4E2D\u2026",
|
|
1810
|
-
historicalPreviewTitle: "\u786E\u8BA4\u5386\u53F2\u4F1A\u8BDD\u8BC4\u6D4B",
|
|
1811
|
-
historicalPreviewHint: "\u8FD9\u91CC\u53EA\u5C55\u793A\u5B89\u5168\u5143\u6570\u636E\u3002\u786E\u8BA4\u524D\u4E0D\u4F1A\u5199\u5165 Batch\uFF0C\u4E5F\u4E0D\u4F1A\u542F\u52A8 Harbor Job\u3002",
|
|
1812
|
-
historicalConfirm: "\u786E\u8BA4\u5E76\u5F00\u59CB\u8BC4\u6D4B",
|
|
1813
|
-
historicalStarting: "\u6B63\u5728\u542F\u52A8\u2026",
|
|
1814
|
-
historicalRunning: "\u5386\u53F2\u4F1A\u8BDD\u8BC4\u6D4B\u8FD0\u884C\u4E2D",
|
|
1815
|
-
historicalRunningHint: "\u53EF\u4EE5\u5173\u95ED\u6B64\u7A97\u53E3\u7EE7\u7EED\u5DE5\u4F5C\u3002Harbor \u4F1A\u5728\u540E\u53F0\u8FD0\u884C\uFF0C\u5B8C\u6210\u540E\u81EA\u52A8\u6253\u5F00 Job\u3002",
|
|
1816
|
-
historicalActive: "\u67E5\u770B\u8FD0\u884C\u72B6\u6001",
|
|
1817
|
-
historicalActiveShort: "\u67E5\u770B\u72B6\u6001",
|
|
1818
|
-
historicalCompleted: "\u8BC4\u6D4B\u5B8C\u6210\uFF0C\u6B63\u5728\u6253\u5F00 Job\u2026",
|
|
1819
|
-
recentSessions: "\u672C\u6B21\u4F1A\u8BDD\u6837\u672C",
|
|
1820
|
-
selectedSessions: "\u9009\u4E2D\u4F1A\u8BDD",
|
|
1821
|
-
requestEstimate: "\u9884\u8BA1 Judge \u8BF7\u6C42",
|
|
1822
|
-
tokenExpiry: "\u9884\u89C8\u6709\u6548\u671F",
|
|
1823
|
-
generatorRole: "\u751F\u6210\u5668",
|
|
1824
|
-
generatorRoleValue: "\u4EA7\u751F\u8FD9\u4E9B\u4F1A\u8BDD\u7684 DSH Agent",
|
|
1825
|
-
evaluatorIdentity: "\u8BC4\u6D4B\u5668\u8EAB\u4EFD",
|
|
1826
|
-
judgeIdentity: "Judge \u8EAB\u4EFD",
|
|
1827
|
-
coupling: "\u6A21\u578B\u8026\u5408",
|
|
1828
|
-
evidenceRetention: "\u8BC1\u636E\u4FDD\u7559",
|
|
1829
|
-
historicalBoundaries: "\u672C\u6B21\u8FD0\u884C\u8FB9\u754C",
|
|
1830
|
-
historicalBoundaryDetail: "\u4E0D\u8FD0\u884C Candidate \xB7 \u4E0D\u505A\u8BC4\u6D4B\u5668\u5143\u8BC4\u6D4B \xB7 \u4E0D\u8FDB\u5165 Gate / \u664B\u7EA7",
|
|
1831
|
-
feedbackCounts: "\u53CD\u9988",
|
|
1832
|
-
turnCounts: "\u8F6E\u6B21",
|
|
1833
|
-
toolCounts: "\u5DE5\u5177\u8C03\u7528",
|
|
1834
|
-
previewAgain: "\u91CD\u65B0\u9884\u89C8",
|
|
1835
|
-
recent30Days: "\u4EC5\u770B\u6700\u8FD1 30 \u5929",
|
|
1836
|
-
noEligibleHint: "\u5F53\u524D\u5DE5\u4F5C\u7A7A\u95F4\u6CA1\u6709\u7B26\u5408\u6761\u4EF6\u7684\u5DF2\u5B8C\u6210\u9876\u5C42\u4F1A\u8BDD\u3002\u5148\u5728\u8FD9\u4E2A\u76EE\u5F55\u5B8C\u6210\u4E00\u4E2A\u6709\u7528\u6237\u8F93\u5165\u548C Agent \u8F93\u51FA\u7684\u771F\u5B9E\u4EFB\u52A1\uFF0C\u6216\u6539\u7528\u663E\u5F0F Dataset\u3002",
|
|
1837
|
-
narrowScanHint: "\u8FD9\u4E2A\u5DE5\u4F5C\u7A7A\u95F4\u7684\u4F1A\u8BDD\u592A\u591A\u3002\u53EF\u4EE5\u628A\u626B\u63CF\u8303\u56F4\u7F29\u5230\u6700\u8FD1 30 \u5929\u540E\u91CD\u8BD5\u3002",
|
|
1838
|
-
changedSessionHint: "\u9884\u89C8\u540E\u4F1A\u8BDD\u3001\u53CD\u9988\u6216\u5DE5\u4F5C\u7A7A\u95F4\u53D1\u751F\u4E86\u53D8\u5316\u3002\u4E3A\u4E86\u907F\u514D\u8BC4\u9519\u8BC1\u636E\uFF0C\u8BF7\u91CD\u65B0\u9884\u89C8\u3002",
|
|
1839
|
-
historicalGenericError: "\u6CA1\u6709\u542F\u52A8 Job\u3002\u8BF7\u68C0\u67E5\u63D0\u793A\u540E\u91CD\u65B0\u9884\u89C8\u3002",
|
|
1840
|
-
cancel: "\u53D6\u6D88",
|
|
1829
|
+
...HISTORICAL_MESSAGES.zh,
|
|
1841
1830
|
completed: "\u5DF2\u5B8C\u6210",
|
|
1842
1831
|
partial: "\u5B8C\u6210\u4F46\u6709\u5F02\u5E38",
|
|
1843
1832
|
failed: "\u8BFB\u53D6\u5931\u8D25",
|
|
@@ -2144,7 +2133,7 @@ var dictionaries = {
|
|
|
2144
2133
|
jobsHint: "Open a Job, then reach Trial evidence in at most one more interaction.",
|
|
2145
2134
|
workspace: "Workspace",
|
|
2146
2135
|
workspaceSelect: "Select Harbor workspace",
|
|
2147
|
-
empty: "No
|
|
2136
|
+
empty: "No evaluation results yet. Try \u201CEvaluate recent Sessions\u201D to find recent real conversations in this DSH automatically, then confirm to begin.",
|
|
2148
2137
|
askAi: "Ask AI",
|
|
2149
2138
|
askAboutThis: "Ask about this",
|
|
2150
2139
|
currentPage: "Current page",
|
|
@@ -2205,43 +2194,7 @@ var dictionaries = {
|
|
|
2205
2194
|
errorNextPermission: "Check the active Session workspace and its access permissions.",
|
|
2206
2195
|
errorNextMissing: "Refresh the list and confirm that the object still exists.",
|
|
2207
2196
|
errorNextArtifact: "Inspect the Job Artifact / Audit, repair the artifact, and retry.",
|
|
2208
|
-
|
|
2209
|
-
historicalLaunchShort: "Start evaluation",
|
|
2210
|
-
historicalLaunchHint: "Up to 10 \xB7 preview before running",
|
|
2211
|
-
historicalLaunchBody: "Diagnose real tasks already completed by the current DSH Agent without rerunning a Candidate.",
|
|
2212
|
-
historicalPreparing: "Finding eligible Sessions\u2026",
|
|
2213
|
-
historicalPreparingShort: "Loading\u2026",
|
|
2214
|
-
historicalPreviewTitle: "Confirm Historical Session evaluation",
|
|
2215
|
-
historicalPreviewHint: "Only safe metadata is shown. No Batch is written and no Harbor Job starts until you confirm.",
|
|
2216
|
-
historicalConfirm: "Confirm and start evaluation",
|
|
2217
|
-
historicalStarting: "Starting\u2026",
|
|
2218
|
-
historicalRunning: "Historical Session evaluation is running",
|
|
2219
|
-
historicalRunningHint: "You can close this window and keep working. Harbor runs in the background and opens the Job when it completes.",
|
|
2220
|
-
historicalActive: "View run status",
|
|
2221
|
-
historicalActiveShort: "View status",
|
|
2222
|
-
historicalCompleted: "Evaluation complete. Opening the Job\u2026",
|
|
2223
|
-
recentSessions: "Session sample",
|
|
2224
|
-
selectedSessions: "Selected Sessions",
|
|
2225
|
-
requestEstimate: "Estimated Judge requests",
|
|
2226
|
-
tokenExpiry: "Preview expires",
|
|
2227
|
-
generatorRole: "Generator",
|
|
2228
|
-
generatorRoleValue: "The DSH Agent that produced these Sessions",
|
|
2229
|
-
evaluatorIdentity: "Evaluator identity",
|
|
2230
|
-
judgeIdentity: "Judge identity",
|
|
2231
|
-
coupling: "Model coupling",
|
|
2232
|
-
evidenceRetention: "Evidence retention",
|
|
2233
|
-
historicalBoundaries: "Run boundaries",
|
|
2234
|
-
historicalBoundaryDetail: "No Candidate run \xB7 no Evaluator meta-evaluation \xB7 no Gate or promotion",
|
|
2235
|
-
feedbackCounts: "Feedback",
|
|
2236
|
-
turnCounts: "Turns",
|
|
2237
|
-
toolCounts: "Tool calls",
|
|
2238
|
-
previewAgain: "Preview again",
|
|
2239
|
-
recent30Days: "Only last 30 days",
|
|
2240
|
-
noEligibleHint: "No eligible completed top-level Sessions were found in this workspace. Complete a real task here with direct user input and Agent output, or use an explicit Dataset.",
|
|
2241
|
-
narrowScanHint: "This workspace has too many Sessions to scan safely. Narrow the scan to the last 30 days and try again.",
|
|
2242
|
-
changedSessionHint: "A Session, its feedback, or the workspace changed after Preview. Preview again so Harbor cannot evaluate stale evidence.",
|
|
2243
|
-
historicalGenericError: "No Job was started. Review the message and preview again.",
|
|
2244
|
-
cancel: "Cancel",
|
|
2197
|
+
...HISTORICAL_MESSAGES.en,
|
|
2245
2198
|
completed: "Completed",
|
|
2246
2199
|
partial: "Completed with errors",
|
|
2247
2200
|
failed: "Read failed",
|
|
@@ -2472,23 +2425,23 @@ for (const locale of ["zh", "en"]) Object.assign(dictionaries[locale], JOURNEY_M
|
|
|
2472
2425
|
Object.assign(dictionaries.zh, { prepareDiagnostic: "\u89C4\u5212\u9009\u4E2D\u9879\u7684\u8BCA\u65AD\u5B9E\u9A8C", askDiagnostic: "\u57FA\u4E8E\u8FD9\u7EC4\u5DF2\u51BB\u7ED3\u7684 Trial\uFF0C\u5148\u8BFB\u53D6\u8BC1\u636E\u5E76\u8BF4\u660E\u5171\u540C\u539F\u56E0\u4E0E\u4E0D\u786E\u5B9A\u6027\uFF0C\u518D\u8C03\u7528 harbor_propose_action \u521B\u5EFA diagnostic-evaluation \u8349\u7A3F\u3002\u53EA\u4F7F\u7528\u6B64\u5F15\u7528\u7684\u9009\u4E2D\u4EFB\u52A1\uFF0C\u4E0D\u6269\u5927\u8303\u56F4\u3001\u4E0D\u6539 Candidate \u6216\u8BC4\u5206\u89C4\u5219\u3002\u5B9E\u9645\u6267\u884C\u7531\u6211\u68C0\u67E5\u53C2\u6570\u5E76\u786E\u8BA4\uFF1B\u73B0\u5728\u4E0D\u8981\u8FD0\u884C\u4EFB\u4F55\u8BC4\u6D4B\u3001\u91CD\u8BD5\u3001Gate \u6216\u53D1\u5E03\u3002" });
|
|
2473
2426
|
Object.assign(dictionaries.en, { prepareDiagnostic: "Plan a diagnostic for this selection", askDiagnostic: "Read this frozen Trial selection and explain the common cause and uncertainty, then use harbor_propose_action to propose a diagnostic-evaluation. Use only these selected tasks, without changing Candidate or scoring rules. I will review the parameters and confirm execution. Do not run evaluations, retries, Gate, or deployment now." });
|
|
2474
2427
|
var CSS = `
|
|
2475
|
-
|
|
2428
|
+
|
|
2476
2429
|
.hse-selection-bar .hse-local-actions button{color:inherit}
|
|
2477
|
-
.hse-operation-tray{margin:10px 0;border:1px solid #70cfff55;border-radius:9px;font-size:11px;overflow-wrap:anywhere}.hse-operation-tray button{padding:7px 9px;background:transparent;color:inherit;border:1px solid #70cfff55;border-radius:7px;font:inherit;cursor:pointer}.hse-operation-tray button:disabled{opacity:.5;cursor:not-allowed}.hse-operation-tray .hse-operation-toggle{border:0;width:100%;text-align:left}.hse-operation-list{padding:0 9px 9px;max-height:45vh;overflow:auto}.hse-operation-item{border-top:1px solid #70cfff35;padding:10px 0;line-height:1.6}.hse-operation-item header{display:flex;justify-content:space-between;flex-wrap:wrap;gap:6px}.hse-operation-item p{margin:6px 0}.hse-operation-item code{font-size:9px}.hse-operation-inspection{padding:8px;border:1px solid #e4a23b55;border-radius:7px;margin:8px 0}.hse-operation-inspection label{display:block}.hse-operation-tray button:focus-visible{outline:2px solid #ffca68;outline-offset:2px}@container(max-width:1050px){
|
|
2478
|
-
.hse-journey{padding:18px;margin-bottom:18px;border:1px solid #2875ff35;border-radius:14px;background:#2875ff08}.hse-journey h2{margin:0;font-size:20px}.hse-journey p,.hse-journey li{font-size:13px;line-height:1.7}.hse-journey ol{padding:0;list-style:none}.hse-journey details summary{cursor:pointer}.hse-question{font-size:12px;line-height:1.6;white-space:pre-wrap;overflow-wrap:anywhere}.hse-discussion-history{margin:10px 0;font-size:12px}.hse-discussion-history button{display:block;width:100%;margin:5px 0;padding:7px;text-align:left;color:inherit;border:1px solid #70cfff55;background:transparent;border-radius:6px;cursor:pointer}.hse-draft-notice{padding:10px;border:1px solid #2875ff44;border-radius:8px;font-size:12px;line-height:1.6}.hse-editor-tab[data-dirty=true]:after{content:' \u2022';color:#c78312}.hse-local-actions{flex-wrap:wrap}.hse-answer-unverified>p{font-size:11px;color:#f3c779}.hse-
|
|
2430
|
+
.hse-operation-tray{margin:10px 0;border:1px solid #70cfff55;border-radius:9px;font-size:11px;overflow-wrap:anywhere}.hse-operation-tray button{padding:7px 9px;background:transparent;color:inherit;border:1px solid #70cfff55;border-radius:7px;font:inherit;cursor:pointer}.hse-operation-tray button:disabled{opacity:.5;cursor:not-allowed}.hse-operation-tray .hse-operation-toggle{border:0;width:100%;text-align:left}.hse-operation-list{padding:0 9px 9px;max-height:45vh;overflow:auto}.hse-operation-item{border-top:1px solid #70cfff35;padding:10px 0;line-height:1.6}.hse-operation-item header{display:flex;justify-content:space-between;flex-wrap:wrap;gap:6px}.hse-operation-item p{margin:6px 0}.hse-operation-item code{font-size:9px}.hse-operation-inspection{padding:8px;border:1px solid #e4a23b55;border-radius:7px;margin:8px 0}.hse-operation-inspection label{display:block}.hse-operation-tray button:focus-visible{outline:2px solid #ffca68;outline-offset:2px}@container(max-width:1050px){}
|
|
2431
|
+
.hse-journey{padding:18px;margin-bottom:18px;border:1px solid #2875ff35;border-radius:14px;background:#2875ff08}.hse-journey h2{margin:0;font-size:20px}.hse-journey p,.hse-journey li{font-size:13px;line-height:1.7}.hse-journey ol{padding:0;list-style:none}.hse-journey details summary{cursor:pointer}.hse-question{font-size:12px;line-height:1.6;white-space:pre-wrap;overflow-wrap:anywhere}.hse-discussion-history{margin:10px 0;font-size:12px}.hse-discussion-history button{display:block;width:100%;margin:5px 0;padding:7px;text-align:left;color:inherit;border:1px solid #70cfff55;background:transparent;border-radius:6px;cursor:pointer}.hse-draft-notice{padding:10px;border:1px solid #2875ff44;border-radius:8px;font-size:12px;line-height:1.6}.hse-editor-tab[data-dirty=true]:after{content:' \u2022';color:#c78312}.hse-local-actions{flex-wrap:wrap}.hse-answer-unverified>p{font-size:11px;color:#f3c779}.hse-job-identities>summary{cursor:pointer;font-size:12px}.hse-job-identities[open]>.hse-identity-tags{margin-top:12px}
|
|
2479
2432
|
.hse-root{--ocean-950:#03152f;--ocean-800:#07366f;--ocean-600:#1464c8;--ocean-300:#75b7ff;--foam-50:#f4fbff;--whale-500:#2875ff;--coral-500:#ee6478;--amber-500:#e4a23b;--kelp-500:#1f9b72;height:100%;min-height:0;overflow:auto;color:var(--dsw-alias-label-primary,#142038);background:var(--dsw-alias-bg-layer-1,#f2f7fc);font-family:inherit}.hse-page{width:min(1320px,calc(100% - 36px));margin:auto;padding:24px 0 56px}
|
|
2480
2433
|
.hse-dashboard-back{margin-bottom:10px}
|
|
2481
|
-
.hse-action-draft button{padding:7px 10px;border:1px solid #70cfff55;border-radius:7px;background:transparent;color:inherit;cursor:pointer;font:inherit}.hse-action-draft>.hse-primary{background:#2875ff;color:#fff;border-color:#2875ff}.hse-action-draft header{flex-wrap:wrap}.hse-action-draft header>span{font-size:10px;color:#a8d9ff}.hse-action-recovery,.hse-action-next-step{padding:8px;margin:8px 0;border:1px solid #e4a23b55;border-radius:8px}.hse-action-comparison{overflow:auto}.hse-action-comparison table{width:100%;border-collapse:collapse}.hse-action-comparison th,.hse-action-comparison td{padding:6px;border-bottom:1px solid #70cfff35;text-align:left}.hse-action-collapsed{display:flex;gap:10px;align-items:center}.hse-
|
|
2434
|
+
.hse-action-draft button{padding:7px 10px;border:1px solid #70cfff55;border-radius:7px;background:transparent;color:inherit;cursor:pointer;font:inherit}.hse-action-draft>.hse-primary{background:#2875ff;color:#fff;border-color:#2875ff}.hse-action-draft header{flex-wrap:wrap}.hse-action-draft header>span{font-size:10px;color:#a8d9ff}.hse-action-recovery,.hse-action-next-step{padding:8px;margin:8px 0;border:1px solid #e4a23b55;border-radius:8px}.hse-action-comparison{overflow:auto}.hse-action-comparison table{width:100%;border-collapse:collapse}.hse-action-comparison th,.hse-action-comparison td{padding:6px;border-bottom:1px solid #70cfff35;text-align:left}.hse-action-collapsed{display:flex;gap:10px;align-items:center}.hse-editor-actions{flex-wrap:wrap}
|
|
2482
2435
|
.hse-root-switch{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:8px;margin:16px 0 8px;padding:14px;border:1px solid #2875ff42;border-radius:12px;background:#2875ff0b}.hse-root-switch label{grid-column:1/-1;font-size:11px;font-weight:700}.hse-root-switch input{min-width:0;padding:10px 12px;border:1px solid #c8d6e7;border-radius:8px;color:inherit;background:var(--dsw-alias-bg-layer-2,#fff);font:11px ui-monospace,SFMono-Regular,Menlo,monospace}.hse-root-switch button{padding:9px 13px;border:0;border-radius:8px;color:#fff;background:var(--ocean-600);cursor:pointer}.hse-root-switch small{grid-column:1/-1;color:var(--dsw-alias-label-secondary,#748096)}
|
|
2483
2436
|
.hse-hero{position:relative;isolation:isolate;overflow:hidden;min-height:225px;padding:32px;border-radius:24px;color:#fff;background:var(--ocean-950) var(--ocean-image) center/cover no-repeat;box-shadow:0 22px 65px #03152f38}.hse-hero:before{content:"";position:absolute;inset:0;z-index:-1;background:linear-gradient(90deg,#02132fea,#062b62d6 55%,#0e6dc42e)}.hse-hero:after{content:"";position:absolute;width:220px;height:220px;right:8%;bottom:-170px;border:1px solid #8be9ff66;border-radius:50%;box-shadow:0 0 0 28px #68dfff0b,0 0 0 60px #68dfff08;animation:hse-ripple 5s ease-out infinite}.hse-hero h1{max-width:780px;margin:15px 0 10px;font-size:clamp(28px,4vw,46px);line-height:1.08;letter-spacing:-.04em}.hse-hero p{max-width:760px;margin:0;color:#d9eeff;font-size:14px;line-height:1.75}.hse-eyebrow{color:#86e8ff;font-size:11px;font-weight:800;letter-spacing:.17em}.hse-whale{margin-right:8px;font-size:17px}.hse-refresh{position:absolute;right:22px;top:22px;padding:8px 13px;border:1px solid #ffffff52;border-radius:999px;color:#fff;background:#06245eb8;cursor:pointer}.hse-stats{display:flex;gap:9px;margin-top:24px;flex-wrap:wrap}.hse-stat{min-width:130px;padding:11px 13px;border:1px solid #ffffff29;border-radius:13px;background:#031a41a8;backdrop-filter:blur(8px)}.hse-stat span{display:block;color:#cde7fb;font-size:10px}.hse-stat b{display:block;margin-top:4px;font-size:20px}.hse-head{margin:28px 0 12px}.hse-head h2{margin:0;font-size:18px}.hse-head p{margin:4px 0 0;color:#728097;font-size:12px}
|
|
2484
2437
|
.hse-list{display:grid;gap:10px}.hse-job{display:block;width:100%;padding:0;border:1px solid var(--dsw-alias-border-l1,#d7e2ef);border-radius:16px;color:inherit;background:var(--dsw-alias-bg-layer-2,#fff);text-align:left;cursor:pointer;overflow:hidden;box-shadow:0 5px 18px #1736600d;transition:.18s ease}.hse-job:hover,.hse-job:focus-visible{border-color:var(--ocean-300);transform:translateY(-1px);outline:3px solid #2875ff20}.hse-job-body{padding:16px 18px}.hse-job-top{display:flex;justify-content:space-between;gap:14px}.hse-job-title{min-width:0}.hse-job-title strong{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:14px}.hse-job-title small{display:block;margin-top:4px;color:#7b879c;font-size:10px}.hse-status{flex:none;padding:5px 9px;border-radius:999px;color:#126d50;background:#23ba8318;font-size:10px;font-weight:700}.hse-status:before{content:"\u2713 ";}.hse-status[data-status=running],.hse-status[data-status=pending]{color:#245dcc;background:#2875ff18}.hse-status[data-status=running]:before{content:"\u25CF ";animation:hse-pulse 1.6s ease-in-out infinite}.hse-status[data-status=partial],.hse-status[data-status=attention]{color:#8e5b0c;background:#e4a23b1b}.hse-status[data-status=partial]:before,.hse-status[data-status=attention]:before{content:"\u25B3 "}.hse-status[data-status=failed]{color:#b52f45;background:#ee647818}.hse-status[data-status=failed]:before{content:"\xD7 "}.hse-meta-grid{display:grid;grid-template-columns:1.35fr 1fr .9fr .65fr .75fr .75fr;gap:7px;margin-top:13px}.hse-meta{min-width:0;padding:8px 9px;border-radius:9px;background:var(--dsw-alias-bg-layer-1,#f3f7fb)}.hse-meta span{display:block;color:#7b879c;font-size:9px}.hse-meta b,.hse-meta code{display:block;margin-top:3px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:10px}.hse-progress{height:5px;margin-top:11px;border-radius:99px;background:#dbe8f5;overflow:hidden}.hse-progress i{display:block;height:100%;background:linear-gradient(90deg,var(--ocean-600),#54d7f5);transition:width .3s}.hse-metrics{display:flex;gap:6px;flex-wrap:wrap;margin-top:10px}.hse-pill{padding:5px 7px;border:1px solid var(--dsw-alias-border-l1,#dce4f0);border-radius:7px;font-size:10px}.hse-pill b{margin-left:5px;color:var(--ocean-600)}
|
|
2485
2438
|
.hse-empty,.hse-error{padding:34px;border:1px dashed #c4d3e5;border-radius:16px;text-align:center;background:var(--dsw-alias-bg-layer-2,#fff);color:var(--dsw-alias-label-secondary,#728097);font-size:12px}.hse-spin{width:25px;height:25px;margin:0 auto 10px;border:3px solid #2875ff22;border-top-color:var(--whale-500);border-radius:50%;animation:hse-spin .8s linear infinite}.hse-button,.hse-close,.hse-ask{border:0;border-radius:9px;padding:8px 11px;color:#fff;background:var(--whale-500);cursor:pointer}.hse-drawer{width:100%;min-height:0;background:var(--dsw-alias-bg-layer-1,#f2f7fc)}.hse-drawer-head{position:sticky;top:0;z-index:5;display:flex;justify-content:space-between;gap:15px;padding:14px 0;border-bottom:1px solid var(--dsw-alias-border-l1,#dce4f0);background:color-mix(in srgb,var(--dsw-alias-bg-layer-1,#f2f7fc) 94%,transparent);backdrop-filter:blur(12px)}.hse-drawer-head h2{margin:0;font-size:18px}.hse-drawer-head p{margin:5px 0 0;color:var(--dsw-alias-label-secondary,#748096);font-size:10px}.hse-drawer-actions{display:flex;align-items:flex-start;gap:7px}.hse-close{align-self:flex-start;background:var(--ocean-950)}.hse-workbench{padding:14px 0 48px}.hse-stage-nav{position:sticky;top:68px;z-index:4;display:grid;grid-template-columns:repeat(9,minmax(88px,1fr));gap:5px;margin:-1px -1px 14px;padding:8px;border:1px solid var(--dsw-alias-border-l1,#d7e2ef);border-radius:13px;background:color-mix(in srgb,var(--dsw-alias-bg-layer-2,#fff) 94%,transparent);backdrop-filter:blur(10px);overflow:auto}.hse-stage-nav button{padding:9px 7px;border:0;border-radius:8px;color:var(--dsw-alias-label-secondary,#52627b);background:transparent;font:inherit;font-size:10px;cursor:pointer;white-space:nowrap}.hse-stage-nav button[data-active=true]{color:#fff;background:var(--ocean-600)}.hse-stage-nav button:focus-visible{outline:3px solid #2875ff2f}.hse-capability{margin-bottom:12px;padding:10px 12px;border-left:3px solid var(--amber-500);border-radius:8px;background:#e4a23b14;color:var(--dsw-alias-label-primary,#75500f);font-size:11px}.hse-section{margin-bottom:13px;padding:16px;border:1px solid var(--dsw-alias-border-l1,#d7e2ef);border-radius:14px;background:var(--dsw-alias-bg-layer-2,#fff)}.hse-section h3{margin:0 0 11px;font-size:14px}.hse-kpis{display:grid;grid-template-columns:repeat(5,minmax(0,1fr));gap:8px}.hse-kpi{padding:11px;border-radius:10px;background:color-mix(in srgb,var(--dsw-alias-bg-layer-1,#edf7ff) 88%,var(--ocean-600) 12%)}.hse-kpi span{display:block;color:var(--dsw-alias-label-secondary,#748096);font-size:9px}.hse-kpi b{display:block;margin-top:4px;font-size:17px}.hse-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:9px}.hse-card{min-width:0;padding:11px;border-radius:10px;background:var(--dsw-alias-bg-layer-1,#f3f7fb)}.hse-card span,.hse-card b,.hse-card code{display:block}.hse-card span{color:var(--dsw-alias-label-secondary,#748096);font-size:9px}.hse-card b,.hse-card code{margin-top:4px;overflow-wrap:anywhere;font-size:10px}.hse-valid{color:var(--kelp-500)}.hse-invalid{color:#bd3148}.hse-muted{color:var(--dsw-alias-label-secondary,#75839a)}.hse-findings{display:grid;gap:6px}.hse-finding{padding:9px 10px;border-left:3px solid var(--ocean-300);border-radius:7px;background:#2875ff0c;font-size:10px}.hse-finding[data-level=error]{border-color:var(--coral-500);background:#ee64780d}.hse-finding[data-level=warning]{border-color:var(--amber-500);background:#e4a23b0d}.hse-components{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:7px}.hse-component{padding:10px;border-radius:9px;background:#0b4c9c12}.hse-component span{display:block;color:var(--dsw-alias-label-secondary,#748096);font-size:9px}.hse-component b,.hse-component code{display:block;margin-top:3px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:9px}
|
|
2486
|
-
.hse-trial-layout{display:grid;grid-template-columns:minmax(380px,1fr) minmax(360px,.9fr);gap:10px;align-items:start}.hse-trial-list,.hse-trial-detail{min-width:0}.hse-trial-tools{display:grid;grid-template-columns:minmax(150px,1fr) auto auto auto;gap:6px;margin-bottom:9px}.hse-input,.hse-select{min-width:0;padding:8px 9px;border:1px solid #c8d6e7;border-radius:8px;color:inherit;background:transparent;font:inherit;font-size:10px}.hse-table-wrap{overflow:auto}.hse-table{width:100%;border-collapse:collapse;font-size:10px}.hse-table th,.hse-table td{padding:8px;border-bottom:1px solid #e2eaf3;text-align:left;white-space:nowrap}.hse-table button{border:0;color:var(--ocean-600);background:none;cursor:pointer;font:inherit}.hse-table tr[data-selected=true]{background:#2875ff0c}.hse-pager{display:flex;justify-content:flex-end;align-items:center;gap:8px;margin-top:9px;font-size:10px}.hse-pager button{padding:5px 8px;border:1px solid #c8d6e7;border-radius:7px;background:transparent;color:inherit;cursor:pointer}.hse-trial-detail{position:sticky;top:132px;max-height:calc(100vh - 160px);overflow:auto;padding:14px;border-radius:12px;color:#dcecff;background:var(--ocean-950)}.hse-trial-score{display:flex;justify-content:space-between;gap:12px;padding-bottom:12px;border-bottom:1px solid #ffffff1f}.hse-trial-score b{font-size:25px}.hse-trial-score span{font-size:10px}.hse-detail-group{padding:11px 0;border-bottom:1px solid #ffffff16}.hse-detail-group h4{margin:0 0 7px;color:#8fe8ff;font-size:10px;text-transform:uppercase;letter-spacing:.08em}.hse-detail-group pre{max-height:280px;overflow:auto;margin:0;white-space:pre-wrap;word-break:break-word;font-size:9px;line-height:1.55}.hse-detail-group ul{margin:0;padding-left:17px;font-size:10px;line-height:1.6}.hse-criteria{display:grid;gap:5px}.hse-criterion{display:flex;justify-content:space-between;gap:8px;padding:7px;border-radius:6px;background:#ffffff0b;font-size:10px}.hse-provenance{display:flex;gap:5px;flex-wrap:wrap}.hse-provenance span{padding:5px 7px;border:1px solid #70cfff4a;border-radius:999px;font-size:9px}.hse-audit summary{cursor:pointer;font-size:11px;font-weight:700}.hse-audit pre,.hse-source{max-height:360px;overflow:auto;white-space:pre-wrap;word-break:break-word;font-size:9px;line-height:1.55}.hse-compare-select{display:flex;gap:7px;margin-bottom:10px}.hse-compare-select select{flex:1}.hse-delta{font-variant-numeric:tabular-nums}.hse-delta[data-positive=true]{color:var(--kelp-500)}.hse-delta[data-positive=false]{color:var(--coral-500)}.hse-source{padding:10px;border-radius:8px;color:#d9edff;background:var(--ocean-950)}.hse-settings{width:min(850px,calc(100% - 32px));margin:auto;padding:28px 0}.hse-checks{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:9px;margin-top:16px}.hse-check{padding:12px;border:1px solid #dce4f0;border-radius:10px;background:var(--dsw-alias-bg-layer-2,#fff)}.hse-check b,.hse-check small{display:block}.hse-check small{margin-top:4px;color:#748096}.hse-tool{border:1px solid #dce4f0;border-radius:11px;background:var(--dsw-alias-bg-layer-2,#fff);overflow:hidden}.hse-tool
|
|
2487
|
-
.hse-trial-layout{display:grid;grid-template-columns:minmax(380px,1fr) minmax(360px,.9fr);gap:10px;align-items:start}.hse-trial-list,.hse-trial-detail{min-width:0}.hse-trial-tools{display:grid;grid-template-columns:minmax(150px,1fr) auto auto auto;gap:6px;margin-bottom:9px}.hse-trial-list-state{display:flex;align-items:center;justify-content:space-between;gap:10px;margin-bottom:9px;padding:9px 11px;border-left:3px solid var(--amber-500);border-radius:8px;background:#e4a23b14;font-size:10px}.hse-trial-list-state[data-stale=false]{border-color:var(--coral-500);background:#ee647812}.hse-trial-list-state div{min-width:0}.hse-trial-list-state b,.hse-trial-list-state small{display:block}.hse-trial-list-state small{margin-top:3px;overflow-wrap:anywhere;color:var(--dsw-alias-label-secondary,#748096)}.hse-trial-list-state button{flex:none;padding:5px 9px;border:1px solid currentColor;border-radius:7px;color:var(--ocean-600);background:transparent;cursor:pointer;font:inherit}.hse-input,.hse-select{min-width:0;padding:8px 9px;border:1px solid #c8d6e7;border-radius:8px;color:inherit;background:transparent;font:inherit;font-size:10px}.hse-table-wrap{overflow:auto}.hse-table{width:100%;border-collapse:collapse;font-size:10px}.hse-table th,.hse-table td{padding:8px;border-bottom:1px solid #e2eaf3;text-align:left;white-space:nowrap}.hse-table button{border:0;color:var(--ocean-600);background:none;cursor:pointer;font:inherit}.hse-table tr[data-selected=true]{background:#2875ff0c}.hse-pager{display:flex;justify-content:flex-end;align-items:center;gap:8px;margin-top:9px;font-size:10px}.hse-pager button{padding:5px 8px;border:1px solid #c8d6e7;border-radius:7px;background:transparent;color:inherit;cursor:pointer}.hse-trial-detail{position:sticky;top:132px;max-height:calc(100vh - 160px);overflow:auto;padding:14px;border-radius:12px;color:#dcecff;background:var(--ocean-950)}.hse-trial-score{display:flex;justify-content:space-between;gap:12px;padding-bottom:12px;border-bottom:1px solid #ffffff1f}.hse-trial-score b{font-size:25px}.hse-trial-score span{font-size:10px}.hse-detail-group{padding:11px 0;border-bottom:1px solid #ffffff16}.hse-detail-group h4{margin:0 0 7px;color:#8fe8ff;font-size:10px;text-transform:uppercase;letter-spacing:.08em}.hse-detail-group pre{max-height:280px;overflow:auto;margin:0;white-space:pre-wrap;word-break:break-word;font-size:9px;line-height:1.55}.hse-detail-group ul{margin:0;padding-left:17px;font-size:10px;line-height:1.6}.hse-criteria{display:grid;gap:5px}.hse-criterion{display:flex;align-items:center;justify-content:space-between;gap:8px;padding:7px;border-radius:6px;background:#ffffff0b;font-size:10px}.hse-criterion[data-highlight=true]{outline:2px solid #86e8ff;background:#1464c84a;animation:hse-focus-flash 2.2s ease-out}.hse-inline-ask{flex:none;padding:4px 7px;border:1px solid #70cfff66;border-radius:999px;color:#dcecff;background:transparent;cursor:pointer;font:inherit;font-size:8px}.hse-provenance{display:flex;gap:5px;flex-wrap:wrap}.hse-provenance button{padding:5px 7px;border:1px solid #70cfff4a;border-radius:999px;color:#dcecff;background:transparent;cursor:pointer;font:inherit;font-size:9px}.hse-audit summary{cursor:pointer;font-size:11px;font-weight:700}.hse-audit pre,.hse-source{max-height:360px;overflow:auto;white-space:pre-wrap;word-break:break-word;font-size:9px;line-height:1.55}.hse-compare-select{display:flex;gap:7px;margin-bottom:10px}.hse-compare-select select{flex:1}.hse-delta{font-variant-numeric:tabular-nums}.hse-delta[data-positive=true]{color:var(--kelp-500)}.hse-delta[data-positive=false]{color:var(--coral-500)}.hse-source{padding:10px;border-radius:8px;color:#d9edff;background:var(--ocean-950)}.hse-settings{width:min(850px,calc(100% - 32px));margin:auto;padding:28px 0}.hse-checks{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:9px;margin-top:16px}.hse-check{padding:12px;border:1px solid #dce4f0;border-radius:10px;background:var(--dsw-alias-bg-layer-2,#fff)}.hse-check b,.hse-check small{display:block}.hse-check small{margin-top:4px;color:#748096}.hse-tool{border:1px solid #dce4f0;border-radius:11px;background:var(--dsw-alias-bg-layer-2,#fff);overflow:hidden}.hse-tool
|
|
2439
|
+
.hse-trial-layout{display:grid;grid-template-columns:minmax(380px,1fr) minmax(360px,.9fr);gap:10px;align-items:start}.hse-trial-list,.hse-trial-detail{min-width:0}.hse-trial-tools{display:grid;grid-template-columns:minmax(150px,1fr) auto auto auto;gap:6px;margin-bottom:9px}.hse-input,.hse-select{min-width:0;padding:8px 9px;border:1px solid #c8d6e7;border-radius:8px;color:inherit;background:transparent;font:inherit;font-size:10px}.hse-table-wrap{overflow:auto}.hse-table{width:100%;border-collapse:collapse;font-size:10px}.hse-table th,.hse-table td{padding:8px;border-bottom:1px solid #e2eaf3;text-align:left;white-space:nowrap}.hse-table button{border:0;color:var(--ocean-600);background:none;cursor:pointer;font:inherit}.hse-table tr[data-selected=true]{background:#2875ff0c}.hse-pager{display:flex;justify-content:flex-end;align-items:center;gap:8px;margin-top:9px;font-size:10px}.hse-pager button{padding:5px 8px;border:1px solid #c8d6e7;border-radius:7px;background:transparent;color:inherit;cursor:pointer}.hse-trial-detail{position:sticky;top:132px;max-height:calc(100vh - 160px);overflow:auto;padding:14px;border-radius:12px;color:#dcecff;background:var(--ocean-950)}.hse-trial-score{display:flex;justify-content:space-between;gap:12px;padding-bottom:12px;border-bottom:1px solid #ffffff1f}.hse-trial-score b{font-size:25px}.hse-trial-score span{font-size:10px}.hse-detail-group{padding:11px 0;border-bottom:1px solid #ffffff16}.hse-detail-group h4{margin:0 0 7px;color:#8fe8ff;font-size:10px;text-transform:uppercase;letter-spacing:.08em}.hse-detail-group pre{max-height:280px;overflow:auto;margin:0;white-space:pre-wrap;word-break:break-word;font-size:9px;line-height:1.55}.hse-detail-group ul{margin:0;padding-left:17px;font-size:10px;line-height:1.6}.hse-criteria{display:grid;gap:5px}.hse-criterion{display:flex;justify-content:space-between;gap:8px;padding:7px;border-radius:6px;background:#ffffff0b;font-size:10px}.hse-provenance{display:flex;gap:5px;flex-wrap:wrap}.hse-provenance span{padding:5px 7px;border:1px solid #70cfff4a;border-radius:999px;font-size:9px}.hse-audit summary{cursor:pointer;font-size:11px;font-weight:700}.hse-audit pre,.hse-source{max-height:360px;overflow:auto;white-space:pre-wrap;word-break:break-word;font-size:9px;line-height:1.55}.hse-compare-select{display:flex;gap:7px;margin-bottom:10px}.hse-compare-select select{flex:1}.hse-delta{font-variant-numeric:tabular-nums}.hse-delta[data-positive=true]{color:var(--kelp-500)}.hse-delta[data-positive=false]{color:var(--coral-500)}.hse-source{padding:10px;border-radius:8px;color:#d9edff;background:var(--ocean-950)}.hse-settings{width:min(850px,calc(100% - 32px));margin:auto;padding:28px 0}.hse-checks{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:9px;margin-top:16px}.hse-check{padding:12px;border:1px solid #dce4f0;border-radius:10px;background:var(--dsw-alias-bg-layer-2,#fff)}.hse-check b,.hse-check small{display:block}.hse-check small{margin-top:4px;color:#748096}.hse-tool{border:1px solid #dce4f0;border-radius:11px;background:var(--dsw-alias-bg-layer-2,#fff);overflow:hidden}.hse-tool>button{display:flex;gap:8px;width:100%;padding:10px;border:0;color:inherit;background:transparent;text-align:left;cursor:pointer}.hse-tool strong{font-size:11px}.hse-tool small{margin-left:auto}.hse-tool>pre{max-height:260px;overflow:auto;margin:0;padding:11px;border-top:1px solid #e3e9f1;white-space:pre-wrap;font-size:9px}
|
|
2440
|
+
.hse-trial-layout{display:grid;grid-template-columns:minmax(380px,1fr) minmax(360px,.9fr);gap:10px;align-items:start}.hse-trial-list,.hse-trial-detail{min-width:0}.hse-trial-tools{display:grid;grid-template-columns:minmax(150px,1fr) auto auto auto;gap:6px;margin-bottom:9px}.hse-trial-list-state{display:flex;align-items:center;justify-content:space-between;gap:10px;margin-bottom:9px;padding:9px 11px;border-left:3px solid var(--amber-500);border-radius:8px;background:#e4a23b14;font-size:10px}.hse-trial-list-state[data-stale=false]{border-color:var(--coral-500);background:#ee647812}.hse-trial-list-state div{min-width:0}.hse-trial-list-state b,.hse-trial-list-state small{display:block}.hse-trial-list-state small{margin-top:3px;overflow-wrap:anywhere;color:var(--dsw-alias-label-secondary,#748096)}.hse-trial-list-state button{flex:none;padding:5px 9px;border:1px solid currentColor;border-radius:7px;color:var(--ocean-600);background:transparent;cursor:pointer;font:inherit}.hse-input,.hse-select{min-width:0;padding:8px 9px;border:1px solid #c8d6e7;border-radius:8px;color:inherit;background:transparent;font:inherit;font-size:10px}.hse-table-wrap{overflow:auto}.hse-table{width:100%;border-collapse:collapse;font-size:10px}.hse-table th,.hse-table td{padding:8px;border-bottom:1px solid #e2eaf3;text-align:left;white-space:nowrap}.hse-table button{border:0;color:var(--ocean-600);background:none;cursor:pointer;font:inherit}.hse-table tr[data-selected=true]{background:#2875ff0c}.hse-pager{display:flex;justify-content:flex-end;align-items:center;gap:8px;margin-top:9px;font-size:10px}.hse-pager button{padding:5px 8px;border:1px solid #c8d6e7;border-radius:7px;background:transparent;color:inherit;cursor:pointer}.hse-trial-detail{position:sticky;top:132px;max-height:calc(100vh - 160px);overflow:auto;padding:14px;border-radius:12px;color:#dcecff;background:var(--ocean-950)}.hse-trial-score{display:flex;justify-content:space-between;gap:12px;padding-bottom:12px;border-bottom:1px solid #ffffff1f}.hse-trial-score b{font-size:25px}.hse-trial-score span{font-size:10px}.hse-detail-group{padding:11px 0;border-bottom:1px solid #ffffff16}.hse-detail-group h4{margin:0 0 7px;color:#8fe8ff;font-size:10px;text-transform:uppercase;letter-spacing:.08em}.hse-detail-group pre{max-height:280px;overflow:auto;margin:0;white-space:pre-wrap;word-break:break-word;font-size:9px;line-height:1.55}.hse-detail-group ul{margin:0;padding-left:17px;font-size:10px;line-height:1.6}.hse-criteria{display:grid;gap:5px}.hse-criterion{display:flex;align-items:center;justify-content:space-between;gap:8px;padding:7px;border-radius:6px;background:#ffffff0b;font-size:10px}.hse-criterion[data-highlight=true]{outline:2px solid #86e8ff;background:#1464c84a;animation:hse-focus-flash 2.2s ease-out}.hse-inline-ask{flex:none;padding:4px 7px;border:1px solid #70cfff66;border-radius:999px;color:#dcecff;background:transparent;cursor:pointer;font:inherit;font-size:8px}.hse-provenance{display:flex;gap:5px;flex-wrap:wrap}.hse-provenance button{padding:5px 7px;border:1px solid #70cfff4a;border-radius:999px;color:#dcecff;background:transparent;cursor:pointer;font:inherit;font-size:9px}.hse-audit summary{cursor:pointer;font-size:11px;font-weight:700}.hse-audit pre,.hse-source{max-height:360px;overflow:auto;white-space:pre-wrap;word-break:break-word;font-size:9px;line-height:1.55}.hse-compare-select{display:flex;gap:7px;margin-bottom:10px}.hse-compare-select select{flex:1}.hse-delta{font-variant-numeric:tabular-nums}.hse-delta[data-positive=true]{color:var(--kelp-500)}.hse-delta[data-positive=false]{color:var(--coral-500)}.hse-source{padding:10px;border-radius:8px;color:#d9edff;background:var(--ocean-950)}.hse-settings{width:min(850px,calc(100% - 32px));margin:auto;padding:28px 0}.hse-checks{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:9px;margin-top:16px}.hse-check{padding:12px;border:1px solid #dce4f0;border-radius:10px;background:var(--dsw-alias-bg-layer-2,#fff)}.hse-check b,.hse-check small{display:block}.hse-check small{margin-top:4px;color:#748096}.hse-tool{border:1px solid #dce4f0;border-radius:11px;background:var(--dsw-alias-bg-layer-2,#fff);overflow:hidden}.hse-tool>button{display:flex;gap:8px;width:100%;padding:10px;border:0;color:inherit;background:transparent;text-align:left;cursor:pointer}.hse-tool strong{font-size:11px}.hse-tool small{margin-left:auto}.hse-tool>pre{max-height:260px;overflow:auto;margin:0;padding:11px;border-top:1px solid #e3e9f1;white-space:pre-wrap;font-size:9px}.hse-tool-action{border-top:1px solid #e3e9f1!important;color:var(--ocean-600)!important;font-weight:700}
|
|
2488
2441
|
.hse-inline-ask[data-highlight=true],.hse-provenance button[data-highlight=true]{outline:2px solid #86e8ff;background:#1464c84a;animation:hse-focus-flash 2.2s ease-out}
|
|
2489
|
-
.hse-context-
|
|
2490
|
-
|
|
2491
|
-
|
|
2442
|
+
.hse-context-flags{display:flex;gap:5px}.hse-context-flags em{padding:3px 6px;border-radius:999px;color:#8e5b0c;background:#e4a23b1b;font-size:8px;font-style:normal}.hse-context-error{color:#bd3148}
|
|
2443
|
+
|
|
2444
|
+
|
|
2492
2445
|
.hse-error-state{display:flex;align-items:flex-start;justify-content:space-between;gap:12px;padding:13px;border-left:4px solid var(--coral-500);border-radius:10px;background:#ee647812;text-align:left}.hse-error-state>div{min-width:0}.hse-error-state b,.hse-error-state span,.hse-error-state small{display:block;overflow-wrap:anywhere}.hse-error-state b{color:#bd3148;font-size:11px}.hse-error-state span{margin-top:4px;font-size:10px}.hse-error-state small{margin-top:5px;color:var(--dsw-alias-label-secondary,#748096);font-size:9px;line-height:1.5}.hse-error-state button,.hse-filter-empty button{flex:none;padding:6px 9px;border:1px solid currentColor;border-radius:7px;color:var(--ocean-600);background:transparent;cursor:pointer;font:inherit;font-size:9px}.hse-error-state[data-category=permission]{border-color:var(--amber-500);background:#e4a23b14}.hse-error-state[data-category=permission] b{color:#8e5b0c}
|
|
2493
2446
|
.hse-skeleton{display:grid;gap:9px;min-height:150px;padding:16px;border:1px solid var(--dsw-alias-border-l1,#d7e2ef);border-radius:14px;background:var(--dsw-alias-bg-layer-2,#fff)}.hse-skeleton i{display:block;height:17px;border-radius:7px;background:linear-gradient(90deg,#dce6f2 20%,#eef4fa 45%,#dce6f2 70%);background-size:240% 100%;animation:hse-skeleton 1.3s ease-in-out infinite}.hse-skeleton i:first-child{height:30px;width:44%}.hse-skeleton i:nth-child(3n){width:72%}.hse-skeleton[data-kind=dashboard]{grid-template-columns:repeat(2,minmax(0,1fr));min-height:230px}.hse-skeleton[data-kind=dashboard] i:first-child{grid-column:1/-1;width:52%;height:38px}.hse-skeleton[data-kind=trial-detail]{min-height:420px;background:var(--ocean-950);border-color:#70cfff32}.hse-skeleton[data-kind=trial-detail] i{background:linear-gradient(90deg,#ffffff0d 20%,#ffffff20 45%,#ffffff0d 70%);background-size:240% 100%}.hse-filter-empty{display:grid;justify-items:center;gap:9px;min-height:120px;padding:24px;border:1px dashed #c4d3e5;border-radius:12px;color:var(--dsw-alias-label-secondary,#728097);background:var(--dsw-alias-bg-layer-2,#fff);text-align:center;font-size:10px}
|
|
2494
2447
|
.hse-job{position:relative;cursor:default}.hse-job-open{display:block;width:100%;padding:0;border:0;color:inherit;background:transparent;text-align:left;cursor:pointer}.hse-job-open:focus-visible{outline:3px solid #2875ff20;outline-offset:-3px}.hse-job-body{padding-right:104px}.hse-job-ask{position:absolute;right:16px;bottom:14px;padding:7px 10px;border:0;border-radius:8px;color:#fff;background:var(--whale-500);cursor:pointer;font:inherit;font-size:9px;font-weight:800}.hse-trial-name{display:flex;align-items:center;gap:7px}.hse-trial-name .hse-trial-ask{padding:3px 6px;border:1px solid #2875ff42;border-radius:999px;font-size:8px}.hse-criterion{flex-wrap:wrap}.hse-criterion>span{margin-right:auto}.hse-context-link:disabled,.hse-job-ask:disabled{opacity:.5;cursor:wait}
|
|
@@ -2504,13 +2457,13 @@ var CSS = `
|
|
|
2504
2457
|
@media(max-width:520px){.hse-hero{min-height:auto;padding:22px}.hse-hero h1{font-size:30px}.hse-stats{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));width:100%}.hse-stat{min-width:0}.hse-launch-card{display:grid;grid-template-columns:38px minmax(0,1fr) 108px;align-items:center;flex-wrap:nowrap}.hse-launch-copy span{display:none}.hse-launch-button{width:100%;margin:0;padding:9px;white-space:normal}.hse-launch-button-full{display:none}.hse-launch-button-short{display:inline}}
|
|
2505
2458
|
@media(prefers-reduced-motion:reduce){.hse-spin,.hse-skeleton i,.hse-status:before,.hse-hero:after,.hse-criterion[data-highlight=true],.hse-inline-ask[data-highlight=true],.hse-provenance button[data-highlight=true]{animation:none}.hse-job{transition:none}.hse-job:hover{transform:none}}
|
|
2506
2459
|
@media(max-width:900px){.hse-report-compare,.hse-meta-flow{grid-template-columns:1fr}.hse-meta-flow div:after{display:none}}
|
|
2507
|
-
.hse-root{container-type:inline-size;overflow:visible}.hse-layout{display:grid;grid-template-columns:minmax(0,1fr)
|
|
2460
|
+
.hse-root{container-type:inline-size;overflow:visible}.hse-layout{display:grid;grid-template-columns:minmax(0,1fr);align-items:start;gap:18px;max-width:1600px}.hse-main-panel{grid-column:1;grid-row:1;min-width:0}.hse-layout .hse-drawer{width:100%;max-width:none}.hse-layout .hse-drawer-head{position:static}
|
|
2508
2461
|
.hse-health-summary{padding:20px;margin-bottom:16px;border:1px solid var(--dsw-alias-border-l1,#d7e2ef);border-radius:16px;background:var(--dsw-alias-bg-layer-2,#fff)}.hse-health-summary h1{margin:6px 0;font-size:22px}.hse-health-summary small{letter-spacing:.07em;color:var(--ocean-600);font-size:10px}.hse-health-filters{display:flex;gap:8px;flex-wrap:wrap}.hse-health-filters button{display:grid;gap:7px;min-width:104px;flex:1;padding:12px;border:1px solid var(--dsw-alias-border-l1,#d7e2ef);border-radius:10px;background:transparent;color:inherit;cursor:pointer;text-align:left}.hse-health-filters button[aria-pressed=true]{border-color:var(--ocean-600);background:#2875ff12}.hse-health-filters span{font-size:11px}.hse-health-filters b{font-size:21px}.hse-attention-label{display:block;font-size:11px;color:var(--ocean-600);margin:5px 0}.hse-attention-label[data-kind=blocked],.hse-attention-label[data-kind=invalid]{color:var(--coral-500)}
|
|
2509
2462
|
.hse-object-nav{display:flex;flex-wrap:wrap;gap:5px;padding:8px 0 14px;border-bottom:1px solid var(--dsw-alias-border-l1,#d7e2ef);margin-bottom:16px}.hse-object-nav button{padding:9px 12px;border:0;border-radius:8px;color:inherit;background:transparent;cursor:pointer;font:inherit;font-size:12px}.hse-object-nav button[aria-current=page]{color:#fff;background:var(--ocean-600);font-weight:700}.hse-job-identities{padding:12px 20px;border-bottom:1px solid var(--dsw-alias-border-l1,#d7e2ef)}.hse-identity-tags{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:10px}.hse-identity-tags span{display:grid;gap:4px;min-width:0}.hse-identity-tags small{font-size:10px;color:var(--dsw-alias-label-secondary,#748096)}.hse-identity-tags b{font-size:11px;overflow-wrap:anywhere}.hse-identity-tags code{font-size:9px;overflow-wrap:anywhere}.hse-identity-flags{display:flex;flex-wrap:wrap;gap:10px;margin-top:10px;font-size:10px}.hse-summary-status{display:flex;justify-content:space-between;align-items:start;gap:12px}.hse-summary-status p{font-size:12px;line-height:1.6;color:var(--dsw-alias-label-secondary,#748096)}.hse-summary-metrics{display:grid;grid-template-columns:repeat(auto-fit,minmax(170px,1fr));gap:10px;margin:15px 0}.hse-summary-metric{padding:14px;border-radius:10px;background:#2875ff0a}.hse-summary-metric>span{display:block;font-size:11px}.hse-summary-metric>strong{display:block;margin:8px 0;font-size:24px}.hse-summary-links{display:flex;gap:8px;flex-wrap:wrap}
|
|
2510
|
-
.hse-local-actions{display:flex;gap:6px;flex-wrap:wrap;align-items:center;margin-top:8px}.hse-local-actions button{border:1px solid #2875ff45;border-radius:6px;padding:5px 7px;background:transparent;color:var(--ocean-600);cursor:pointer;font-size:10px}.hse-local-actions code{font-size:9px;overflow-wrap:anywhere}.hse-root [data-highlight=true]{outline:2px solid #2896ff;outline-offset:3px;background:#2875ff14}.hse-
|
|
2511
|
-
@container(max-width:1050px){.hse-layout{grid-template-columns:minmax(0,1fr)}.hse-
|
|
2512
|
-
.hse-
|
|
2513
|
-
.hse-action-draft{padding:12px;margin:10px 0;border:1px solid #70cfff55;border-radius:10px;font-size:11px}.hse-action-draft header{display:flex;justify-content:space-between;gap:8px}.hse-action-draft dl{display:grid;grid-template-columns:80px minmax(0,1fr);gap:5px;margin:10px 0}.hse-action-draft dd{margin:0;overflow-wrap:anywhere}.hse-action-draft code{font-size:9px;overflow-wrap:anywhere}.hse-action-draft pre{white-space:pre-wrap;overflow-wrap:anywhere;max-height:240px;overflow:auto}.hse-action-preview{padding:10px;margin:8px 0;border:1px solid #e4a23b55;border-radius:7px;font-size:11px}.hse-action-preview>code{display:block;overflow-wrap:anywhere;font-size:9px}.hse-
|
|
2463
|
+
.hse-local-actions{display:flex;gap:6px;flex-wrap:wrap;align-items:center;margin-top:8px}.hse-local-actions button{border:1px solid #2875ff45;border-radius:6px;padding:5px 7px;background:transparent;color:var(--ocean-600);cursor:pointer;font-size:10px}.hse-local-actions code{font-size:9px;overflow-wrap:anywhere}.hse-root [data-highlight=true]{outline:2px solid #2896ff;outline-offset:3px;background:#2875ff14}.hse-source-fragment textarea{width:100%;min-height:180px;padding:12px;border:1px solid #2875ff45;border-radius:8px;background:var(--dsw-alias-bg-layer-1,#f3f7fb);color:inherit;font:11px/1.6 monospace}.hse-diff-grid{display:grid;grid-template-columns:1fr 1fr;gap:10px}.hse-diff-grid pre{max-height:280px;overflow:auto;white-space:pre-wrap;overflow-wrap:anywhere}.hse-answer-unverified{padding:8px;border:1px solid #e4a23b73;border-radius:8px;font-size:11px}.hse-answer-unverified button{margin-top:8px;border:1px solid #70cfff55;border-radius:6px;background:transparent;color:inherit;padding:6px;cursor:pointer}
|
|
2464
|
+
@container(max-width:1050px){.hse-layout{grid-template-columns:minmax(0,1fr)}.hse-identity-tags{grid-template-columns:repeat(2,minmax(0,1fr))}.hse-trial-layout,.hse-output-layout,.hse-report-compare{grid-template-columns:1fr}.hse-trial-detail{position:static;max-height:none}.hse-meta-grid{grid-template-columns:repeat(2,minmax(0,1fr))}.hse-diff-grid{grid-template-columns:1fr}}
|
|
2465
|
+
.hse-selection-bar{padding:10px;margin:8px 0;border:1px solid #2875ff25;border-radius:8px;font-size:11px}.hse-selection-bar code{font-size:9px;overflow-wrap:anywhere}.hse-saved-source textarea{min-height:180px}
|
|
2466
|
+
.hse-action-draft{padding:12px;margin:10px 0;border:1px solid #70cfff55;border-radius:10px;font-size:11px}.hse-action-draft header{display:flex;justify-content:space-between;gap:8px}.hse-action-draft dl{display:grid;grid-template-columns:80px minmax(0,1fr);gap:5px;margin:10px 0}.hse-action-draft dd{margin:0;overflow-wrap:anywhere}.hse-action-draft code{font-size:9px;overflow-wrap:anywhere}.hse-action-draft pre{white-space:pre-wrap;overflow-wrap:anywhere;max-height:240px;overflow:auto}.hse-action-preview{padding:10px;margin:8px 0;border:1px solid #e4a23b55;border-radius:7px;font-size:11px}.hse-action-preview>code{display:block;overflow-wrap:anywhere;font-size:9px}.hse-action-draft button:disabled{opacity:.45;cursor:not-allowed}
|
|
2514
2467
|
`;
|
|
2515
2468
|
function installStyles() {
|
|
2516
2469
|
const id = "dsh-harbor-evolution/client";
|
|
@@ -3063,9 +3016,6 @@ function harborTurnProjection(nodes, token) {
|
|
|
3063
3016
|
const projected = candidates.filter((node) => turn === void 0 || !Number.isFinite(node?.turn) || node.turn === turn);
|
|
3064
3017
|
return { nodes: projected, active: boundaryIndex === values.length, anchorSeq, turn };
|
|
3065
3018
|
}
|
|
3066
|
-
function assistantText(node) {
|
|
3067
|
-
return Array.isArray(node?.blocks) ? node.blocks.filter((block) => block?.kind === "text").map((block) => block.text).join("\n") : "";
|
|
3068
|
-
}
|
|
3069
3019
|
function toolResultValue(node) {
|
|
3070
3020
|
if (!node || node.kind !== "tool-result" || node.isError) return void 0;
|
|
3071
3021
|
if (isRecord(node.value)) return node.value;
|
|
@@ -3154,12 +3104,6 @@ function ContextFlags({ context, t }) {
|
|
|
3154
3104
|
].filter(Boolean);
|
|
3155
3105
|
return values.length ? /* @__PURE__ */ import_react5.default.createElement("span", { className: "hse-context-flags" }, values.map((value) => /* @__PURE__ */ import_react5.default.createElement("em", { key: value }, value))) : null;
|
|
3156
3106
|
}
|
|
3157
|
-
function harborReferenceIdentity(reference) {
|
|
3158
|
-
const value = reference?.ref ?? reference?.action?.target ?? {};
|
|
3159
|
-
const parts = [value.job, value.trial, value.criterion, value.evidenceRef].filter(Boolean);
|
|
3160
|
-
if (parts.length) return parts.join(" / ");
|
|
3161
|
-
return value.id ?? reference?.action?.target?.route ?? "\u2014";
|
|
3162
|
-
}
|
|
3163
3107
|
function harborSubmissionTransition(submitted, explicit, phase, hasReference) {
|
|
3164
3108
|
let pending = submitted;
|
|
3165
3109
|
if (explicit && hasReference && ["adjudicating", "submitting"].includes(phase)) pending = explicit;
|
|
@@ -3267,47 +3211,20 @@ function removeContextPart(context, part) {
|
|
|
3267
3211
|
}
|
|
3268
3212
|
return next;
|
|
3269
3213
|
}
|
|
3270
|
-
function
|
|
3214
|
+
function HarborInputSync({ bridge, sessionId, useInput, replaceHarborReference }) {
|
|
3271
3215
|
const ui = useHarborUi(bridge, sessionId);
|
|
3272
|
-
const dockNode = (0, import_react5.useRef)();
|
|
3273
3216
|
const draft = useInput((state) => state?.draft ?? "");
|
|
3274
3217
|
const phase = useInput((state) => state?.phase ?? "plain");
|
|
3275
|
-
const phaseRef = (0, import_react5.useRef)(phase);
|
|
3276
|
-
phaseRef.current = phase;
|
|
3277
3218
|
const occurrences = useInput((state) => state?.occurrences ?? []);
|
|
3278
3219
|
const submitted = (0, import_react5.useRef)();
|
|
3279
3220
|
const observedTokens = (0, import_react5.useRef)(/* @__PURE__ */ new Set());
|
|
3280
|
-
const [clock, setClock] = (0, import_react5.useState)(Date.now);
|
|
3281
3221
|
const explicit = ui.explicit;
|
|
3282
3222
|
const token = explicit?.contextSnapshotId;
|
|
3283
3223
|
const hasReference = hasHarborReference(draft, occurrences, token);
|
|
3284
|
-
const expiry = Date.parse(explicit?.expiresAt ?? "");
|
|
3285
|
-
const expired = isExplicitContextExpired(explicit?.expiresAt, clock);
|
|
3286
|
-
(0, import_react5.useEffect)(() => {
|
|
3287
|
-
const measure = () => {
|
|
3288
|
-
const top = dockNode.current?.getBoundingClientRect().top;
|
|
3289
|
-
if (Number.isFinite(top) && bridge.getSnapshot(sessionId).composerTop !== Math.floor(top)) bridge.update(sessionId, { composerTop: Math.floor(top) });
|
|
3290
|
-
};
|
|
3291
|
-
const frame = window.requestAnimationFrame(measure);
|
|
3292
|
-
const observer = new ResizeObserver(measure);
|
|
3293
|
-
if (dockNode.current) observer.observe(dockNode.current);
|
|
3294
|
-
window.addEventListener("resize", measure);
|
|
3295
|
-
return () => {
|
|
3296
|
-
window.cancelAnimationFrame(frame);
|
|
3297
|
-
observer.disconnect();
|
|
3298
|
-
window.removeEventListener("resize", measure);
|
|
3299
|
-
};
|
|
3300
|
-
}, [bridge, sessionId, draft, phase, token]);
|
|
3301
3224
|
(0, import_react5.useEffect)(() => {
|
|
3302
3225
|
if (!explicit || isHarborInputBusy(phase) || !needsStructuredHarborNormalization(draft, occurrences, explicit, observedTokens.current.has(token))) return;
|
|
3303
3226
|
replaceHarborReference?.(explicit, "");
|
|
3304
3227
|
}, [draft, explicit, occurrences, phase, replaceHarborReference, token]);
|
|
3305
|
-
(0, import_react5.useEffect)(() => {
|
|
3306
|
-
setClock(Date.now());
|
|
3307
|
-
if (!Number.isFinite(expiry) || expiry <= Date.now()) return void 0;
|
|
3308
|
-
const timer = window.setTimeout(() => setClock(Date.now()), Math.min(expiry - Date.now() + 25, 2147483647));
|
|
3309
|
-
return () => window.clearTimeout(timer);
|
|
3310
|
-
}, [expiry]);
|
|
3311
3228
|
(0, import_react5.useEffect)(() => {
|
|
3312
3229
|
if (token && hasReference) observedTokens.current.add(token);
|
|
3313
3230
|
const wasObserved = Boolean(token && observedTokens.current.has(token));
|
|
@@ -3322,63 +3239,7 @@ function ContextDock({ bridge, sessionId, useInput, useSession, stop, inputActio
|
|
|
3322
3239
|
observedTokens.current.delete(token);
|
|
3323
3240
|
}
|
|
3324
3241
|
}, [bridge, explicit, hasReference, phase, sessionId, token]);
|
|
3325
|
-
|
|
3326
|
-
if (!context || !inputActions) return void 0;
|
|
3327
|
-
return bridge.issue(sessionId, context, { forceNew: true });
|
|
3328
|
-
};
|
|
3329
|
-
const update = async (context) => {
|
|
3330
|
-
try {
|
|
3331
|
-
const issued = await bind(context);
|
|
3332
|
-
commitIssuedDraft(bridge, sessionId, issued, replaceHarborReference, "", phaseRef.current, true);
|
|
3333
|
-
return issued;
|
|
3334
|
-
} catch {
|
|
3335
|
-
return void 0;
|
|
3336
|
-
}
|
|
3337
|
-
};
|
|
3338
|
-
const clear = () => {
|
|
3339
|
-
if (clearHarborReferences?.() !== true) return;
|
|
3340
|
-
bridge.clearExplicit(sessionId, token);
|
|
3341
|
-
};
|
|
3342
|
-
const removePart = async (part) => {
|
|
3343
|
-
const context = removeContextPart(explicit?.context, part);
|
|
3344
|
-
if (!context) {
|
|
3345
|
-
clear();
|
|
3346
|
-
return;
|
|
3347
|
-
}
|
|
3348
|
-
await update(context);
|
|
3349
|
-
};
|
|
3350
|
-
const capsuleContext = explicit?.context;
|
|
3351
|
-
const capsuleParts = capsuleContext ? [
|
|
3352
|
-
{ key: "job", label: capsuleContext.object?.job ? `Job ${capsuleContext.object.job}` : `Harbor ${capsuleContext.workspace}` },
|
|
3353
|
-
...capsuleContext.object?.trial ? [{ key: "trial", label: `Trial ${capsuleContext.object.trial}` }] : [],
|
|
3354
|
-
...(capsuleContext.selection ?? []).map((ref, index) => ({ key: `selection-${index}`, label: `${ref.kind}${ref.selectionCount ? ` (${ref.selectionCount})` : ""} \xB7 ${ref.criterion ?? ref.evidenceRef ?? short(ref.id)}${ref.startLine ? ` \xB7 L${ref.startLine}\u2013${ref.endLine}` : ""}` }))
|
|
3355
|
-
] : [];
|
|
3356
|
-
const ask = async (prompt, context) => {
|
|
3357
|
-
if (expired) return;
|
|
3358
|
-
try {
|
|
3359
|
-
const reusingExplicit = Boolean(explicit && !context);
|
|
3360
|
-
const issued = reusingExplicit ? explicit : await bind(context ?? ui.current);
|
|
3361
|
-
if (!issued) return;
|
|
3362
|
-
commitIssuedDraft(bridge, sessionId, issued, replaceHarborReference, prompt, phaseRef.current, !reusingExplicit);
|
|
3363
|
-
} catch {
|
|
3364
|
-
}
|
|
3365
|
-
};
|
|
3366
|
-
return /* @__PURE__ */ import_react5.default.createElement(HarborSessionContext.Provider, { value: sessionId }, /* @__PURE__ */ import_react5.default.createElement("div", { className: "hse-input-dock", ref: dockNode }, ui.workbenchDock?.narrow ? /* @__PURE__ */ import_react5.default.createElement("aside", { className: "hse-mobile-copilot" }, /* @__PURE__ */ import_react5.default.createElement(CopilotDock, { bridge, sessionId, useSession, stop, resolveLatest: ui.workbenchDock.resolveLatest, reanalyzeLatest: ui.workbenchDock.reanalyzeLatest, prepareQuestion: ui.workbenchDock.prepareQuestion, t })) : null, /* @__PURE__ */ import_react5.default.createElement("section", { className: "hse-context-dock", "aria-live": "polite" }, /* @__PURE__ */ import_react5.default.createElement("div", { className: "hse-context-line" }, /* @__PURE__ */ import_react5.default.createElement("strong", null, t("currentPage")), ui.current ? /* @__PURE__ */ import_react5.default.createElement(import_react5.default.Fragment, null, /* @__PURE__ */ import_react5.default.createElement("span", { className: "hse-context-chip" }, /* @__PURE__ */ import_react5.default.createElement("span", null, contextLabel(ui.current))), /* @__PURE__ */ import_react5.default.createElement(ContextFlags, { context: ui.current, t }), /* @__PURE__ */ import_react5.default.createElement("button", { type: "button", className: "hse-context-link", disabled: ui.status === "binding", onClick: () => void update(ui.current) }, explicit ? t("updateContext") : t("askAboutThis"))) : /* @__PURE__ */ import_react5.default.createElement("span", { className: "hse-muted" }, "Harbor \u2014")), /* @__PURE__ */ import_react5.default.createElement("div", { className: "hse-context-line" }, /* @__PURE__ */ import_react5.default.createElement("strong", null, t("turnContext")), explicit ? /* @__PURE__ */ import_react5.default.createElement(import_react5.default.Fragment, null, /* @__PURE__ */ import_react5.default.createElement("span", { className: "hse-context-chip" }, /* @__PURE__ */ import_react5.default.createElement("span", null, explicit.context.route?.params?.stage ?? "Harbor"), /* @__PURE__ */ import_react5.default.createElement("button", { type: "button", "aria-label": t("clearContext"), disabled: isHarborInputBusy(phase), onClick: clear }, t("clearContext"), " \xD7")), /* @__PURE__ */ import_react5.default.createElement(ContextFlags, { context: explicit.context, t }), expired ? /* @__PURE__ */ import_react5.default.createElement(import_react5.default.Fragment, null, /* @__PURE__ */ import_react5.default.createElement("em", { className: "hse-context-error" }, t("contextExpired")), /* @__PURE__ */ import_react5.default.createElement("small", null, t("contextExpiredHint")), /* @__PURE__ */ import_react5.default.createElement("button", { type: "button", className: "hse-context-link", disabled: !ui.current || ui.status === "binding", onClick: () => void update(ui.current) }, t("updateContext"))) : /* @__PURE__ */ import_react5.default.createElement("small", null, t("oneShot"))) : /* @__PURE__ */ import_react5.default.createElement("span", { className: "hse-muted" }, ui.status === "binding" ? t("bindingContext") : t("noTurnContext"))), explicit ? /* @__PURE__ */ import_react5.default.createElement("div", { className: "hse-capsule-parts" }, capsuleParts.map((part) => /* @__PURE__ */ import_react5.default.createElement("span", { className: "hse-context-chip", key: part.key }, /* @__PURE__ */ import_react5.default.createElement("span", null, part.label), /* @__PURE__ */ import_react5.default.createElement("button", { type: "button", "aria-label": `${t("clearContext")} ${part.label}`, disabled: isHarborInputBusy(phase) || ui.status === "binding", onClick: () => void removePart(part.key) }, "\xD7"))), /* @__PURE__ */ import_react5.default.createElement("details", { className: "hse-context-identity" }, /* @__PURE__ */ import_react5.default.createElement("summary", null, t("contextIdentity")), /* @__PURE__ */ import_react5.default.createElement("pre", null, pretty2({ ...capsuleContext, contextSnapshotId: explicit.contextSnapshotId, expiresAt: explicit.expiresAt })))) : null, ui.error ? /* @__PURE__ */ import_react5.default.createElement(HarborErrorState, { error: ui.error, title: t("contextBindFailed"), t }) : null, ui.current ? /* @__PURE__ */ import_react5.default.createElement("div", { className: "hse-context-questions", "aria-label": t("questionSuggestions") }, harborQuestionKeys(explicit?.context ?? ui.current).map((key) => /* @__PURE__ */ import_react5.default.createElement("button", { type: "button", key, disabled: expired || isHarborInputBusy(phase) || ui.status === "binding", onClick: () => void ask(t(key)) }, t(harborQuestionLabelKey(key)))), ui.lastSent?.context && !explicit ? /* @__PURE__ */ import_react5.default.createElement("button", { type: "button", disabled: isHarborInputBusy(phase) || ui.status === "binding", title: t("followupHint"), onClick: () => void ask("", ui.lastSent.context) }, t("continueObject")) : null) : null)));
|
|
3367
|
-
}
|
|
3368
|
-
function AnswerText({ text }) {
|
|
3369
|
-
const lines = String(text ?? "").split("\n");
|
|
3370
|
-
let code = false;
|
|
3371
|
-
const inline = (line) => line.split(/(`[^`]+`)/g).map((part, i) => part.startsWith("`") && part.endsWith("`") ? /* @__PURE__ */ import_react5.default.createElement("code", { key: i }, part.slice(1, -1)) : part);
|
|
3372
|
-
return /* @__PURE__ */ import_react5.default.createElement("div", { className: "hse-answer-text" }, lines.map((line, index) => {
|
|
3373
|
-
if (line.startsWith("```")) {
|
|
3374
|
-
code = !code;
|
|
3375
|
-
return /* @__PURE__ */ import_react5.default.createElement("hr", { key: index });
|
|
3376
|
-
}
|
|
3377
|
-
if (code) return /* @__PURE__ */ import_react5.default.createElement("pre", { key: index }, line || " ");
|
|
3378
|
-
if (/^#{1,4} /.test(line)) return /* @__PURE__ */ import_react5.default.createElement("h4", { key: index }, inline(line.replace(/^#{1,4} /, "")));
|
|
3379
|
-
if (/^[-*] /.test(line)) return /* @__PURE__ */ import_react5.default.createElement("p", { className: "hse-answer-bullet", key: index }, "\u2022 ", inline(line.slice(2)));
|
|
3380
|
-
return line.trim() ? /* @__PURE__ */ import_react5.default.createElement("p", { key: index }, inline(line)) : null;
|
|
3381
|
-
}));
|
|
3242
|
+
return null;
|
|
3382
3243
|
}
|
|
3383
3244
|
function ActionDraftCard({ draft, onSourceDraft, onReprepare, onViewComparison, onViewResult, t }) {
|
|
3384
3245
|
const update = useHarborMutation();
|
|
@@ -3436,40 +3297,19 @@ function actionDraftContext(draft, sessionId, pageSessionId) {
|
|
|
3436
3297
|
}
|
|
3437
3298
|
return context;
|
|
3438
3299
|
}
|
|
3439
|
-
function
|
|
3440
|
-
const
|
|
3441
|
-
|
|
3442
|
-
|
|
3443
|
-
|
|
3444
|
-
|
|
3445
|
-
const latestSequence = (0, import_react5.useRef)(0);
|
|
3446
|
-
const ui = useHarborUi(bridge, sessionId);
|
|
3447
|
-
const nodes = useSession((state) => state?.nodes ?? []);
|
|
3448
|
-
(0, import_react5.useEffect)(() => {
|
|
3449
|
-
if (bridge.getSnapshot(sessionId).lastSent) return;
|
|
3450
|
-
const recovered = recoverHarborTurn(nodes, sessionId);
|
|
3451
|
-
if (recovered) bridge.update(sessionId, { lastSent: recovered });
|
|
3452
|
-
}, [bridge, nodes, sessionId]);
|
|
3453
|
-
const partial = useSession((state) => state?.partial ?? null);
|
|
3454
|
-
const runningCalls = useSession((state) => state?.runningCalls ?? []);
|
|
3455
|
-
const running = useSession((state) => Boolean(state?.running));
|
|
3456
|
-
const lastAgentError = useSession((state) => state?.lastAgentError ?? null);
|
|
3457
|
-
const projection = harborConversationProjection(nodes, ui.lastSent?.contextSnapshotId, selectedSeq);
|
|
3458
|
-
const recent = projection.nodes;
|
|
3459
|
-
const completed = [...recent].reverse().find((node) => node?.kind === "assistant");
|
|
3460
|
-
const answer = projection.active && running && partial ? assistantText(partial) : assistantText(completed);
|
|
3461
|
-
const settledTools = recent.filter((node) => node?.kind === "tool-result").map((node) => node.call?.name ?? node.callId).filter(Boolean);
|
|
3462
|
-
const references = trustedHarborReferences(recent);
|
|
3463
|
-
const action = toolUiAction(recent) ?? ui.pendingAction;
|
|
3464
|
-
const resolved = trustedHarborResolvedContext(recent);
|
|
3465
|
-
const actionDrafts = recent.filter((node) => node?.call?.name === "harbor_propose_action").map(toolResultValue).filter((value) => value?.schema === "harbor-action-draft/v1" && value?.draftId);
|
|
3300
|
+
function createHarborActionHandlers({ bridge, sessionId, prepareQuestion, onNavigate, t }) {
|
|
3301
|
+
const navigate = (action) => {
|
|
3302
|
+
const accepted = bridge.navigate(sessionId, action, { force: true });
|
|
3303
|
+
onNavigate?.(accepted);
|
|
3304
|
+
return accepted;
|
|
3305
|
+
};
|
|
3466
3306
|
const openSourceDraft = (draft) => {
|
|
3467
3307
|
bridge.update(sessionId, { evaluatorProposal: { ...draft, reviewRequestId: pageSessionIdentity() } });
|
|
3468
3308
|
const ref = draft.proposal?.sourceRef;
|
|
3469
|
-
if (ref)
|
|
3309
|
+
if (ref) navigate({ kind: "harbor.navigate", actionId: `draft-source-${draft.draftId}`, target: { route: "harbor.evaluator", workspace: draft.target.workspace, job: ref.job, stage: "judge" } });
|
|
3470
3310
|
};
|
|
3471
3311
|
const reprepare = async (draft) => {
|
|
3472
|
-
const original = actionDraftContext(draft, sessionId,
|
|
3312
|
+
const original = actionDraftContext(draft, sessionId, bridge.getSnapshot(sessionId).current?.pageSessionId ?? bridge.getSnapshot(sessionId).lastSent?.context?.pageSessionId ?? pageSessionIdentity());
|
|
3473
3313
|
if (!original) return false;
|
|
3474
3314
|
const prepared = await prepareQuestion?.(original, `${t("repreparePrompt")}
|
|
3475
3315
|
${draft.proposal?.summary ?? ""}`);
|
|
@@ -3477,52 +3317,13 @@ ${draft.proposal?.summary ?? ""}`);
|
|
|
3477
3317
|
if (!prepared && ["conflict", "expired"].includes(error?.category)) {
|
|
3478
3318
|
const source = draft.proposal?.sourceRef;
|
|
3479
3319
|
bridge.update(sessionId, { error: { ...error, nextStep: t("draftRecoveryReselect") } });
|
|
3480
|
-
|
|
3320
|
+
navigate({ kind: "harbor.navigate", actionId: `reselect-${draft.draftId}`, target: { route: source ? "harbor.evaluator" : "harbor.job", workspace: draft.target.workspace, job: draft.target.job, stage: source || draft.selection?.some((ref) => /trial-set/.test(ref.kind)) ? "judge" : original.route.params.stage, ...draft.target.trial ? { trial: draft.target.trial } : {} } });
|
|
3481
3321
|
}
|
|
3482
3322
|
return prepared === true;
|
|
3483
3323
|
};
|
|
3484
|
-
const viewComparison = (draft) =>
|
|
3485
|
-
const viewDiagnostic = (draft, result) =>
|
|
3486
|
-
|
|
3487
|
-
const activeRunning = projection.active && running;
|
|
3488
|
-
const relevantError = projection.active ? lastAgentError : null;
|
|
3489
|
-
const turnId = projection.turn ?? projection.anchorSeq;
|
|
3490
|
-
const token = resolved?.contextSnapshotId ?? projection.contextToken ?? ui.lastSent?.contextSnapshotId;
|
|
3491
|
-
const completionId = completed?.messageId ?? completed?.seq;
|
|
3492
|
-
const refreshLatest = (0, import_react5.useCallback)(async () => {
|
|
3493
|
-
if (!token || !resolveLatest) return;
|
|
3494
|
-
const sequence = ++latestSequence.current;
|
|
3495
|
-
try {
|
|
3496
|
-
const value = await resolveLatest(token, sessionId);
|
|
3497
|
-
if (sequence === latestSequence.current) setLatest({ status: "ready", token, turnId, value });
|
|
3498
|
-
} catch (error) {
|
|
3499
|
-
if (sequence !== latestSequence.current) return;
|
|
3500
|
-
const expired = /(?:^|_)EXPIRED\b|\bexpired\b/i.test(`${error?.code ?? ""} ${error?.message ?? ""}`);
|
|
3501
|
-
setLatest({ status: "error", token, turnId, freshness: expired ? "EXPIRED" : "UNAVAILABLE", error: normalizeHarborUiError(error) });
|
|
3502
|
-
}
|
|
3503
|
-
}, [resolveLatest, sessionId, token, turnId]);
|
|
3504
|
-
(0, import_react5.useEffect)(() => {
|
|
3505
|
-
latestSequence.current += 1;
|
|
3506
|
-
if (!token || !completionId || activeRunning || !resolveLatest || !resolved) {
|
|
3507
|
-
setLatest({ status: "idle" });
|
|
3508
|
-
return void 0;
|
|
3509
|
-
}
|
|
3510
|
-
void refreshLatest();
|
|
3511
|
-
const timer = window.setInterval(() => void refreshLatest(), 15e3);
|
|
3512
|
-
return () => {
|
|
3513
|
-
window.clearInterval(timer);
|
|
3514
|
-
latestSequence.current += 1;
|
|
3515
|
-
};
|
|
3516
|
-
}, [activeRunning, completionId, refreshLatest, resolveLatest, token, resolved?.contextSnapshotId]);
|
|
3517
|
-
const currentLatest = latest.token === token ? latest : void 0;
|
|
3518
|
-
const origin = trustedHarborResolvedContext(projection.originNodes ?? []);
|
|
3519
|
-
const discussionContext = resolvedUiContext(resolved ?? origin, sessionId) ?? (token === ui.lastSent?.contextSnapshotId ? ui.lastSent?.context : void 0);
|
|
3520
|
-
const freshness = resolved ? currentLatest?.value?.freshness ?? currentLatest?.freshness ?? resolved.freshness : "UNVERIFIED";
|
|
3521
|
-
const contextSummary = resolved?.context ?? (projection.continuation ? void 0 : discussionContext);
|
|
3522
|
-
const basis = harborDisplayedAnswerBasis(resolved, references, projection.continuation, currentLatest?.value, discussionContext);
|
|
3523
|
-
const stale = freshness === "DRIFTED_READ_ONLY" || freshness === "DRIFTED" || freshness === "EXPIRED";
|
|
3524
|
-
const status = relevantError ? t("copilotFailed") : activeCalls.length ? t("copilotReading") : activeRunning ? t("copilotAnalyzing") : ui.lastSent ? t("fullConversation") : t("copilotIdle");
|
|
3525
|
-
return /* @__PURE__ */ import_react5.default.createElement("section", { className: "hse-copilot", style: !ui.workbenchDock?.narrow && ui.composerTop ? { maxHeight: Math.max(80, ui.composerTop - 120), boxSizing: "border-box" } : void 0, "data-collapsed": String(!expanded), "aria-live": "polite" }, /* @__PURE__ */ import_react5.default.createElement("div", { className: "hse-copilot-head" }, /* @__PURE__ */ import_react5.default.createElement("h3", null, "\u{1F433} ", t("copilot")), /* @__PURE__ */ import_react5.default.createElement("div", { className: "hse-copilot-controls" }, activeRunning && stop ? /* @__PURE__ */ import_react5.default.createElement("button", { type: "button", onClick: () => void stop() }, t("stopAgent")) : null, /* @__PURE__ */ import_react5.default.createElement("button", { type: "button", className: "hse-copilot-toggle", "aria-expanded": expanded, "aria-label": expanded ? t("collapse") : t("expand"), onClick: () => setExpanded((value) => !value) }, expanded ? "\u2212" : "+"))), !expanded ? /* @__PURE__ */ import_react5.default.createElement("p", { className: "hse-copilot-status" }, activeRunning ? status : answer ? t("replyReady") : t("copilotIdle")) : null, /* @__PURE__ */ import_react5.default.createElement(OperationTray, { ...{ sessionId, request, update }, scopeKey: ui.current?.workspace, t: (key) => t(`operationTray_${key}`), onViewResult: (operation, result) => viewDiagnostic(operation, result) }), expanded ? /* @__PURE__ */ import_react5.default.createElement(import_react5.default.Fragment, null, /* @__PURE__ */ import_react5.default.createElement("p", { className: "hse-copilot-status" }, status), projection.turns?.length > 1 ? /* @__PURE__ */ import_react5.default.createElement("details", { className: "hse-discussion-history" }, /* @__PURE__ */ import_react5.default.createElement("summary", null, t("discussionHistory"), " \xB7 ", projection.turns.length), projection.turns.map((item) => /* @__PURE__ */ import_react5.default.createElement("button", { type: "button", key: item.seq, "aria-current": item.seq === projection.selectedSeq ? "true" : void 0, onClick: () => setSelectedSeq(item.seq) }, item.question || t("aiQuestion"))), /* @__PURE__ */ import_react5.default.createElement("button", { type: "button", onClick: () => setSelectedSeq(void 0) }, t("latestReply"))) : null, projection.question ? /* @__PURE__ */ import_react5.default.createElement("div", { className: "hse-question" }, /* @__PURE__ */ import_react5.default.createElement("strong", null, t("aiQuestion")), /* @__PURE__ */ import_react5.default.createElement("p", null, projection.question)) : null, projection.continuation ? /* @__PURE__ */ import_react5.default.createElement("p", { className: "hse-copilot-status" }, t("followupUnbound")) : null, token ? /* @__PURE__ */ import_react5.default.createElement("div", { className: "hse-hook-state" }, /* @__PURE__ */ import_react5.default.createElement("b", null, t("copilotTurn"), ": ", turnId ?? "\u2014"), /* @__PURE__ */ import_react5.default.createElement("br", null), contextSummary ? contextLabel(contextSummary) : basis?.job ? `Job ${basis.job}` : t("historyOnly"), stale ? /* @__PURE__ */ import_react5.default.createElement("p", null, t("contextStale")) : null) : null, answer ? /* @__PURE__ */ import_react5.default.createElement("div", { className: "hse-copilot-answer" }, /* @__PURE__ */ import_react5.default.createElement(AnswerText, { text: answer })) : null, answer && !activeRunning && !references.some((ref) => ref.kind === "evidence" && ref.available) ? /* @__PURE__ */ import_react5.default.createElement("div", { className: "hse-answer-unverified", role: "status" }, /* @__PURE__ */ import_react5.default.createElement("p", null, t("evidenceNotChecked"))) : null, references.length ? /* @__PURE__ */ import_react5.default.createElement("div", { className: "hse-copilot-refs" }, /* @__PURE__ */ import_react5.default.createElement("strong", null, references.some((reference) => reference.kind === "evidence") ? t("evidenceRefs") : t("objectRefs")), references.map((reference) => /* @__PURE__ */ import_react5.default.createElement("button", { type: "button", className: "hse-copilot-ref", "data-available": String(reference.available), key: reference.action.actionId, onClick: () => bridge.navigate(sessionId, reference.action, { force: true }) }, /* @__PURE__ */ import_react5.default.createElement("b", null, reference.label ?? t("viewInHarbor")), /* @__PURE__ */ import_react5.default.createElement("span", null, reference.kind === "evidence" ? t("evidence") : t("objectRefs")), /* @__PURE__ */ import_react5.default.createElement("code", null, harborReferenceIdentity(reference), reference.available ? "" : ` \xB7 ${t("evidenceUnavailable")}`)))) : null, actionDrafts.map((draft) => /* @__PURE__ */ import_react5.default.createElement(ActionDraftCard, { key: draft.draftId, draft, onSourceDraft: openSourceDraft, onReprepare: reprepare, onViewComparison: viewComparison, onViewResult: (result) => viewDiagnostic(draft, result), t })), discussionContext && prepareQuestion ? /* @__PURE__ */ import_react5.default.createElement("div", { className: "hse-copilot-actions" }, /* @__PURE__ */ import_react5.default.createElement("button", { type: "button", disabled: activeRunning || ui.status === "binding", onClick: () => void prepareQuestion(discussionContext, "") }, t("continueObject")), /* @__PURE__ */ import_react5.default.createElement("small", null, t("followupHint"))) : null, basis || activeCalls.length || settledTools.length ? /* @__PURE__ */ import_react5.default.createElement("details", { className: "hse-answer-details" }, /* @__PURE__ */ import_react5.default.createElement("summary", null, t("answerDetails")), /* @__PURE__ */ import_react5.default.createElement("p", null, t("contextFreshness"), ": ", freshness ?? "\u2014"), activeCalls.length || settledTools.length ? /* @__PURE__ */ import_react5.default.createElement("div", { className: "hse-copilot-tools" }, [...activeCalls.map((call) => call.name ?? call.toolName ?? call.callId), ...settledTools].filter(Boolean).map((name2, index) => /* @__PURE__ */ import_react5.default.createElement("span", { key: `${name2}-${index}` }, name2))) : null, basis ? /* @__PURE__ */ import_react5.default.createElement("div", { className: "hse-copilot-basis" }, /* @__PURE__ */ import_react5.default.createElement("strong", null, t("basedOn")), basis.job ? /* @__PURE__ */ import_react5.default.createElement("span", null, "Job", /* @__PURE__ */ import_react5.default.createElement("b", null, basis.job)) : null, basis.artifactRevision ? /* @__PURE__ */ import_react5.default.createElement("span", null, t("revision"), /* @__PURE__ */ import_react5.default.createElement("code", null, short(basis.artifactRevision))) : null, basis.currentRevision && basis.currentRevision !== basis.artifactRevision ? /* @__PURE__ */ import_react5.default.createElement("span", null, t("currentRevision"), /* @__PURE__ */ import_react5.default.createElement("code", null, short(basis.currentRevision))) : null, basis.observedAt ? /* @__PURE__ */ import_react5.default.createElement("span", null, t("observedAt"), /* @__PURE__ */ import_react5.default.createElement("time", { dateTime: basis.observedAt }, new Date(basis.observedAt).toLocaleString())) : null) : null) : null, relevantError ? /* @__PURE__ */ import_react5.default.createElement("div", { className: "hse-context-error" }, relevantError) : null, currentLatest?.status === "error" && freshness !== "EXPIRED" ? /* @__PURE__ */ import_react5.default.createElement(HarborErrorState, { error: currentLatest.error, t }) : null, stale && reanalyzeLatest ? /* @__PURE__ */ import_react5.default.createElement("div", { className: "hse-copilot-actions" }, /* @__PURE__ */ import_react5.default.createElement("button", { type: "button", onClick: () => void reanalyzeLatest(discussionContext) }, t("reanalyzeLatest"))) : null, !references.length && action ? /* @__PURE__ */ import_react5.default.createElement("div", { className: "hse-copilot-actions" }, /* @__PURE__ */ import_react5.default.createElement("button", { type: "button", onClick: () => bridge.navigate(sessionId, action, { force: true }) }, t("viewInHarbor"))) : null) : null);
|
|
3324
|
+
const viewComparison = (draft) => navigate({ kind: "harbor.navigate", actionId: `comparison-${draft.draftId}`, target: { route: "harbor.compare", workspace: draft.target.workspace, job: draft.target.job, stage: "gate", baseline: draft.target.baseline, candidate: draft.target.candidate } });
|
|
3325
|
+
const viewDiagnostic = (draft, result) => navigate({ kind: "harbor.navigate", actionId: `diagnostic-result-${draft.operationId}`, target: { route: "harbor.job", workspace: draft.target.workspace, job: result.jobName, stage: "judge" } });
|
|
3326
|
+
return { openSourceDraft, reprepare, viewComparison, viewDiagnostic };
|
|
3526
3327
|
}
|
|
3527
3328
|
function MetricPills({ metrics }) {
|
|
3528
3329
|
return /* @__PURE__ */ import_react5.default.createElement("div", { className: "hse-metrics" }, Object.entries(metrics ?? {}).map(([key, value]) => /* @__PURE__ */ import_react5.default.createElement("span", { className: "hse-pill", key }, key, /* @__PURE__ */ import_react5.default.createElement("b", null, format2(value)))));
|
|
@@ -4717,25 +4518,24 @@ function historicalError(value) {
|
|
|
4717
4518
|
const code = value?.code ?? message.match(/\b([A-Z][A-Z0-9_]{3,})\b/)?.[1] ?? "HISTORICAL_JOB_FAILED";
|
|
4718
4519
|
return { code, message: message.replace(new RegExp(`^${code}:\\s*`), ""), observedAt: (/* @__PURE__ */ new Date()).toISOString() };
|
|
4719
4520
|
}
|
|
4720
|
-
function historicalErrorHint(code, t) {
|
|
4721
|
-
if (code === "NO_ELIGIBLE_SESSIONS") return t("noEligibleHint");
|
|
4722
|
-
if (code === "SESSION_SELECTION_TOO_EXPENSIVE") return t("narrowScanHint");
|
|
4723
|
-
if (/SESSION_(?:SAMPLE|FEEDBACK)_CHANGED|WORKSPACE_MISMATCH|TOKEN_(?:INVALID|EXPIRED)|PREVIEW_(?:INVALID|WORKSPACE_MISMATCH)/.test(code)) return t("changedSessionHint");
|
|
4724
|
-
return t("historicalGenericError");
|
|
4725
|
-
}
|
|
4726
4521
|
function HistoricalLauncher({ snapshot, reload, onCompleted, t }) {
|
|
4727
4522
|
const request = useHarborApi();
|
|
4728
4523
|
const update = useHarborMutation();
|
|
4729
4524
|
const [state, setState] = (0, import_react5.useState)({ status: "idle" });
|
|
4730
4525
|
const [open, setOpen] = (0, import_react5.useState)(false);
|
|
4526
|
+
const previewSequence = (0, import_react5.useRef)(0);
|
|
4527
|
+
const workspaceGeneration = (0, import_react5.useRef)(0);
|
|
4731
4528
|
const workspace = snapshot?.workspace?.id;
|
|
4732
4529
|
const operationId = state.operation?.operationId;
|
|
4733
4530
|
(0, import_react5.useEffect)(() => {
|
|
4734
4531
|
let alive = true;
|
|
4532
|
+
previewSequence.current += 1;
|
|
4533
|
+
workspaceGeneration.current += 1;
|
|
4735
4534
|
setState({ status: "idle" });
|
|
4736
4535
|
setOpen(false);
|
|
4737
4536
|
if (!workspace) return () => {
|
|
4738
4537
|
alive = false;
|
|
4538
|
+
workspaceGeneration.current += 1;
|
|
4739
4539
|
};
|
|
4740
4540
|
void request("historical-operation", { workspace }).then((operation) => {
|
|
4741
4541
|
if (alive && ["queued", "running"].includes(operation?.status)) {
|
|
@@ -4745,6 +4545,8 @@ function HistoricalLauncher({ snapshot, reload, onCompleted, t }) {
|
|
|
4745
4545
|
});
|
|
4746
4546
|
return () => {
|
|
4747
4547
|
alive = false;
|
|
4548
|
+
previewSequence.current += 1;
|
|
4549
|
+
workspaceGeneration.current += 1;
|
|
4748
4550
|
};
|
|
4749
4551
|
}, [request, workspace]);
|
|
4750
4552
|
(0, import_react5.useEffect)(() => {
|
|
@@ -4756,10 +4558,12 @@ function HistoricalLauncher({ snapshot, reload, onCompleted, t }) {
|
|
|
4756
4558
|
const operation = await request("historical-operation", { workspace, operationId });
|
|
4757
4559
|
if (!alive) return;
|
|
4758
4560
|
if (operation.status === "completed") {
|
|
4561
|
+
const generation = workspaceGeneration.current;
|
|
4562
|
+
const sequence = previewSequence.current;
|
|
4759
4563
|
setState({ status: "completed", operation });
|
|
4760
4564
|
setOpen(false);
|
|
4761
4565
|
await reload(true);
|
|
4762
|
-
if (
|
|
4566
|
+
if (generation === workspaceGeneration.current && sequence === previewSequence.current) onCompleted(operation);
|
|
4763
4567
|
return;
|
|
4764
4568
|
}
|
|
4765
4569
|
if (operation.status === "failed") {
|
|
@@ -4782,38 +4586,45 @@ function HistoricalLauncher({ snapshot, reload, onCompleted, t }) {
|
|
|
4782
4586
|
if (!open) return void 0;
|
|
4783
4587
|
const escape = (event) => {
|
|
4784
4588
|
if (event.key !== "Escape") return;
|
|
4589
|
+
previewSequence.current += 1;
|
|
4785
4590
|
setOpen(false);
|
|
4786
4591
|
if (!["running", "starting"].includes(state.status)) setState({ status: "idle" });
|
|
4787
4592
|
};
|
|
4788
4593
|
window.addEventListener("keydown", escape);
|
|
4789
4594
|
return () => window.removeEventListener("keydown", escape);
|
|
4790
4595
|
}, [open, state.status]);
|
|
4791
|
-
const preview = async (
|
|
4596
|
+
const preview = async () => {
|
|
4597
|
+
const sequence = ++previewSequence.current;
|
|
4792
4598
|
setOpen(true);
|
|
4793
4599
|
setState({ status: "previewing" });
|
|
4794
4600
|
try {
|
|
4795
4601
|
const value = await update("historical-preview", {
|
|
4796
4602
|
workspace,
|
|
4797
|
-
limit:
|
|
4798
|
-
includeFeedback: true
|
|
4799
|
-
...days ? { createdAfter: new Date(Date.now() - days * 864e5).toISOString() } : {}
|
|
4603
|
+
limit: 3,
|
|
4604
|
+
includeFeedback: true
|
|
4800
4605
|
});
|
|
4606
|
+
if (sequence !== previewSequence.current) return;
|
|
4801
4607
|
setState({ status: "ready", preview: value });
|
|
4802
4608
|
} catch (error) {
|
|
4609
|
+
if (sequence !== previewSequence.current) return;
|
|
4803
4610
|
setState({ status: "error", error: historicalError(error) });
|
|
4804
4611
|
}
|
|
4805
4612
|
};
|
|
4806
4613
|
const confirm = async () => {
|
|
4807
4614
|
if (!state.preview) return;
|
|
4615
|
+
const generation = workspaceGeneration.current;
|
|
4808
4616
|
setState((current) => ({ ...current, status: "starting" }));
|
|
4809
4617
|
try {
|
|
4810
4618
|
const operation = await update("historical-run", { workspace, previewId: state.preview.previewId });
|
|
4619
|
+
if (generation !== workspaceGeneration.current) return;
|
|
4811
4620
|
setState({ status: "running", operation });
|
|
4812
4621
|
} catch (error) {
|
|
4622
|
+
if (generation !== workspaceGeneration.current) return;
|
|
4813
4623
|
const normalized = historicalError(error);
|
|
4814
4624
|
if (normalized.code === "HISTORICAL_JOB_ALREADY_RUNNING") {
|
|
4815
4625
|
try {
|
|
4816
4626
|
const operation = await request("historical-operation", { workspace });
|
|
4627
|
+
if (generation !== workspaceGeneration.current) return;
|
|
4817
4628
|
if (["queued", "running"].includes(operation?.status)) {
|
|
4818
4629
|
setState({ status: "running", operation });
|
|
4819
4630
|
return;
|
|
@@ -4821,23 +4632,26 @@ function HistoricalLauncher({ snapshot, reload, onCompleted, t }) {
|
|
|
4821
4632
|
} catch {
|
|
4822
4633
|
}
|
|
4823
4634
|
}
|
|
4635
|
+
if (generation !== workspaceGeneration.current) return;
|
|
4824
4636
|
setState({ status: "error", error: normalized });
|
|
4825
4637
|
}
|
|
4826
4638
|
};
|
|
4827
4639
|
const close = () => {
|
|
4640
|
+
previewSequence.current += 1;
|
|
4828
4641
|
setOpen(false);
|
|
4829
4642
|
if (!["running", "starting"].includes(state.status)) setState({ status: "idle" });
|
|
4830
4643
|
};
|
|
4831
4644
|
const previewValue = state.preview;
|
|
4832
|
-
const evaluator = previewValue?.evaluation?.evaluator;
|
|
4833
4645
|
const judge = previewValue?.evaluation?.judge;
|
|
4834
4646
|
const active = ["running", "starting"].includes(state.status);
|
|
4835
4647
|
const buttonLabel = active ? t("historicalActive") : state.status === "previewing" ? t("historicalPreparing") : t("historicalLaunch");
|
|
4836
4648
|
const buttonShort = active ? t("historicalActiveShort") : state.status === "previewing" ? t("historicalPreparingShort") : t("historicalLaunchShort");
|
|
4837
|
-
|
|
4649
|
+
const dialogTitle = state.status === "error" ? t("historicalErrorTitle") : state.status === "running" ? t("historicalRunning") : state.status === "starting" ? t("historicalStarting") : t("historicalPreviewTitle");
|
|
4650
|
+
const dialogHint = state.status === "error" ? t("historicalErrorBody") : state.status === "running" ? t("historicalRunningHint") : state.status === "starting" ? t("historicalStartingHint") : t("historicalPreviewHint");
|
|
4651
|
+
return /* @__PURE__ */ import_react5.default.createElement(import_react5.default.Fragment, null, /* @__PURE__ */ import_react5.default.createElement("section", { className: "hse-launch-card", "aria-live": "polite" }, /* @__PURE__ */ import_react5.default.createElement("div", { className: "hse-launch-mark", "aria-hidden": "true" }, "\u2726"), /* @__PURE__ */ import_react5.default.createElement("div", { className: "hse-launch-copy" }, /* @__PURE__ */ import_react5.default.createElement("b", null, active ? t("historicalRunning") : t("historicalLaunch")), /* @__PURE__ */ import_react5.default.createElement("span", null, active ? t("historicalRunningHint") : t("historicalLaunchBody")), /* @__PURE__ */ import_react5.default.createElement("small", null, active ? `${state.operation?.selectedCount ?? "\u2014"} ${t("historicalSessionUnit")}` : t("historicalLaunchHint"))), /* @__PURE__ */ import_react5.default.createElement("button", { type: "button", className: "hse-launch-button", disabled: !workspace || state.status === "previewing", onClick: () => active ? setOpen(true) : void preview() }, /* @__PURE__ */ import_react5.default.createElement("span", { className: "hse-launch-button-full" }, buttonLabel), /* @__PURE__ */ import_react5.default.createElement("span", { className: "hse-launch-button-short" }, buttonShort))), open ? /* @__PURE__ */ import_react5.default.createElement("div", { className: "hse-launch-overlay", role: "presentation", onMouseDown: (event) => event.target === event.currentTarget && close() }, /* @__PURE__ */ import_react5.default.createElement("section", { className: "hse-launch-dialog", role: "dialog", "aria-modal": "true", "aria-labelledby": "hse-historical-title" }, /* @__PURE__ */ import_react5.default.createElement("header", { className: "hse-launch-head" }, /* @__PURE__ */ import_react5.default.createElement("div", null, /* @__PURE__ */ import_react5.default.createElement("span", null, t("historicalLaunchHint")), /* @__PURE__ */ import_react5.default.createElement("h2", { id: "hse-historical-title" }, dialogTitle), /* @__PURE__ */ import_react5.default.createElement("p", null, dialogHint)), /* @__PURE__ */ import_react5.default.createElement("button", { type: "button", className: "hse-dialog-close", "aria-label": t("close"), onClick: close }, "\xD7")), /* @__PURE__ */ import_react5.default.createElement("div", { className: "hse-launch-body" }, state.status === "previewing" ? /* @__PURE__ */ import_react5.default.createElement("div", { className: "hse-empty" }, /* @__PURE__ */ import_react5.default.createElement("div", { className: "hse-spin" }), t("historicalPreparing")) : null, state.status === "starting" ? /* @__PURE__ */ import_react5.default.createElement("div", { className: "hse-empty" }, /* @__PURE__ */ import_react5.default.createElement("div", { className: "hse-spin" }), t("historicalStarting")) : null, state.status === "running" ? /* @__PURE__ */ import_react5.default.createElement("div", { className: "hse-run-state" }, /* @__PURE__ */ import_react5.default.createElement("div", { className: "hse-spin" }), /* @__PURE__ */ import_react5.default.createElement("b", null, t("historicalRunning")), /* @__PURE__ */ import_react5.default.createElement("span", null, state.operation?.selectedCount ?? "\u2014", " ", t("historicalSessionUnit")), /* @__PURE__ */ import_react5.default.createElement("p", null, t("historicalRunningHint"))) : null, state.status === "completed" ? /* @__PURE__ */ import_react5.default.createElement("div", { className: "hse-run-state" }, /* @__PURE__ */ import_react5.default.createElement("b", null, "\u2713 ", t("historicalCompleted"))) : null, state.status === "error" ? /* @__PURE__ */ import_react5.default.createElement("section", { className: "hse-launch-section" }, /* @__PURE__ */ import_react5.default.createElement("p", { role: "alert" }, historicalErrorHint(state.error.code, t)), /* @__PURE__ */ import_react5.default.createElement("details", null, /* @__PURE__ */ import_react5.default.createElement("summary", null, t("historicalErrorDetails")), /* @__PURE__ */ import_react5.default.createElement(HarborErrorState, { error: { ...state.error, nextStep: historicalErrorHint(state.error.code, t) }, t }))) : null, state.status === "ready" && previewValue ? /* @__PURE__ */ import_react5.default.createElement(import_react5.default.Fragment, null, /* @__PURE__ */ import_react5.default.createElement("p", { className: "hse-boundary-note" }, t("historicalPrivacyHint")), previewValue.scan?.partial ? /* @__PURE__ */ import_react5.default.createElement("p", { className: "hse-muted" }, t("historicalPartialHint")) : null, previewValue.excludedCounts?.unreadable > 0 ? /* @__PURE__ */ import_react5.default.createElement("p", { className: "hse-muted" }, t("historicalUnreadableHint")) : null, /* @__PURE__ */ import_react5.default.createElement("div", { className: "hse-launch-summary" }, /* @__PURE__ */ import_react5.default.createElement("div", null, /* @__PURE__ */ import_react5.default.createElement("span", null, t("selectedSessions")), /* @__PURE__ */ import_react5.default.createElement("b", null, previewValue.selected.length)), /* @__PURE__ */ import_react5.default.createElement("div", null, /* @__PURE__ */ import_react5.default.createElement("span", null, t("judgeIdentity")), /* @__PURE__ */ import_react5.default.createElement("b", null, judge?.provider ?? "\u2014", " / ", judge?.model ?? "\u2014"))), /* @__PURE__ */ import_react5.default.createElement("section", { className: "hse-launch-section" }, /* @__PURE__ */ import_react5.default.createElement("h3", null, t("recentSessions")), /* @__PURE__ */ import_react5.default.createElement("div", { className: "hse-session-list" }, previewValue.selected.map((session) => /* @__PURE__ */ import_react5.default.createElement("article", { key: session.trialId }, /* @__PURE__ */ import_react5.default.createElement("div", null, /* @__PURE__ */ import_react5.default.createElement("b", null, session.title), /* @__PURE__ */ import_react5.default.createElement("span", null, session.lastActivityAt ? new Date(session.lastActivityAt).toLocaleString() : "\u2014")), /* @__PURE__ */ import_react5.default.createElement("p", null, t("turnCounts"), " ", session.turnCount ?? 0, " \xB7 ", t("toolCounts"), " ", session.toolCallCount ?? 0))))), /* @__PURE__ */ import_react5.default.createElement("details", { className: "hse-launch-section" }, /* @__PURE__ */ import_react5.default.createElement("summary", null, t("historicalBoundaries")), /* @__PURE__ */ import_react5.default.createElement("p", { className: "hse-boundary-note" }, t("historicalBoundaryDetail")))) : null), /* @__PURE__ */ import_react5.default.createElement("footer", { className: "hse-launch-actions" }, state.status === "ready" ? /* @__PURE__ */ import_react5.default.createElement(import_react5.default.Fragment, null, /* @__PURE__ */ import_react5.default.createElement("button", { type: "button", onClick: close }, t("cancel")), /* @__PURE__ */ import_react5.default.createElement("button", { type: "button", className: "hse-confirm", onClick: () => void confirm() }, t("historicalConfirm"))) : null, state.status === "error" ? /* @__PURE__ */ import_react5.default.createElement(import_react5.default.Fragment, null, /* @__PURE__ */ import_react5.default.createElement("button", { type: "button", onClick: close }, t("close")), /* @__PURE__ */ import_react5.default.createElement("button", { type: "button", onClick: () => void preview() }, t("previewAgain"))) : null, state.status === "running" ? /* @__PURE__ */ import_react5.default.createElement("button", { type: "button", onClick: close }, t("close")) : null))) : null);
|
|
4838
4652
|
}
|
|
4839
4653
|
function DashboardView(props) {
|
|
4840
|
-
return /* @__PURE__ */ import_react5.default.createElement(DashboardSessionView, { key: String(props.sessionId), ...props });
|
|
4654
|
+
return /* @__PURE__ */ import_react5.default.createElement(HarborSessionContext.Provider, { value: props.sessionId }, /* @__PURE__ */ import_react5.default.createElement(DashboardSessionView, { key: String(props.sessionId), ...props }));
|
|
4841
4655
|
}
|
|
4842
4656
|
function nearestScrollPort(element) {
|
|
4843
4657
|
for (let node = element; node; node = node.parentElement) {
|
|
@@ -4848,7 +4662,7 @@ function nearestScrollPort(element) {
|
|
|
4848
4662
|
function GettingStarted({ jobs, openJob, t }) {
|
|
4849
4663
|
return /* @__PURE__ */ import_react5.default.createElement("section", { className: "hse-journey", "aria-label": t("journeyTitle") }, /* @__PURE__ */ import_react5.default.createElement("h2", null, t("journeyTitle")), /* @__PURE__ */ import_react5.default.createElement("p", null, t("journeyIntro")), /* @__PURE__ */ import_react5.default.createElement("ol", null, [1, 2, 3].map((step) => /* @__PURE__ */ import_react5.default.createElement("li", { key: step }, t(`journeyStep${step}`)))), jobs?.length ? /* @__PURE__ */ import_react5.default.createElement("button", { type: "button", className: "hse-button", onClick: () => openJob(jobs[0].name) }, t("journeyOpen")) : /* @__PURE__ */ import_react5.default.createElement("p", null, t("journeyEmpty")));
|
|
4850
4664
|
}
|
|
4851
|
-
function DashboardSessionView({ t, bridge,
|
|
4665
|
+
function DashboardSessionView({ t, bridge, sessionId, useInput, inputActions, replaceHarborReference }) {
|
|
4852
4666
|
const [workspace, setWorkspace] = (0, import_react5.useState)("");
|
|
4853
4667
|
const [offset, setOffset] = (0, import_react5.useState)(0);
|
|
4854
4668
|
const [attentionFilter, setAttentionFilter] = (0, import_react5.useState)("all");
|
|
@@ -4881,37 +4695,9 @@ function DashboardSessionView({ t, bridge, stop, sessionId, useSession, useInput
|
|
|
4881
4695
|
return false;
|
|
4882
4696
|
}
|
|
4883
4697
|
}, [bridge, inputActions, replaceHarborReference, sessionId]);
|
|
4884
|
-
const
|
|
4885
|
-
|
|
4886
|
-
|
|
4887
|
-
}, [sessionId]);
|
|
4888
|
-
const reanalyzeLatest = (0, import_react5.useCallback)(async (context) => {
|
|
4889
|
-
if (!context || !inputActions) return;
|
|
4890
|
-
try {
|
|
4891
|
-
const issued = await bridge.issue(sessionId, context, { forceNew: true });
|
|
4892
|
-
commitIssuedDraft(bridge, sessionId, issued, replaceHarborReference, t("reanalyzeLatestPrompt"), phaseRef.current, true);
|
|
4893
|
-
} catch {
|
|
4894
|
-
}
|
|
4895
|
-
}, [bridge, inputActions, replaceHarborReference, sessionId, t]);
|
|
4896
|
-
const dockCallbacks = (0, import_react5.useRef)();
|
|
4897
|
-
dockCallbacks.current = { resolveLatest, reanalyzeLatest, prepareQuestion: askContext };
|
|
4898
|
-
(0, import_react5.useEffect)(() => {
|
|
4899
|
-
let previous;
|
|
4900
|
-
const callbacks = { resolveLatest: (...args) => dockCallbacks.current.resolveLatest(...args), reanalyzeLatest: (...args) => dockCallbacks.current.reanalyzeLatest(...args), prepareQuestion: (...args) => dockCallbacks.current.prepareQuestion(...args) };
|
|
4901
|
-
const publish = (width) => {
|
|
4902
|
-
const narrow = width <= 1050;
|
|
4903
|
-
if (previous === narrow) return;
|
|
4904
|
-
previous = narrow;
|
|
4905
|
-
bridge.update(sessionId, { workbenchDock: { pageSessionId, narrow, ...callbacks } });
|
|
4906
|
-
};
|
|
4907
|
-
if (rootNode.current) publish(rootNode.current.getBoundingClientRect().width);
|
|
4908
|
-
const observer = new ResizeObserver((entries) => publish(entries[0].contentRect.width));
|
|
4909
|
-
if (rootNode.current) observer.observe(rootNode.current);
|
|
4910
|
-
return () => {
|
|
4911
|
-
observer.disconnect();
|
|
4912
|
-
if (bridge.getSnapshot(sessionId).workbenchDock?.pageSessionId === pageSessionId) bridge.update(sessionId, { workbenchDock: void 0 });
|
|
4913
|
-
};
|
|
4914
|
-
}, [bridge, pageSessionId, sessionId]);
|
|
4698
|
+
const request = useHarborApi();
|
|
4699
|
+
const update = useHarborMutation();
|
|
4700
|
+
const viewDiagnostic = (operation, result) => bridge.navigate(sessionId, { kind: "harbor.navigate", actionId: `diagnostic-result-${operation.operationId}`, target: { route: "harbor.job", workspace: operation.target.workspace, job: result.jobName, stage: "judge" } }, { force: true });
|
|
4915
4701
|
const switchWorkspace = (event) => {
|
|
4916
4702
|
navigationHistory.current = [];
|
|
4917
4703
|
setHistoryDepth(0);
|
|
@@ -5021,7 +4807,7 @@ function DashboardSessionView({ t, bridge, stop, sessionId, useSession, useInput
|
|
|
5021
4807
|
bridge.acknowledgeNavigation(sessionId, action.actionId);
|
|
5022
4808
|
}, [bridge, offset, selected, sessionId, snapshot?.workspace?.id, ui.navigation, workspace]);
|
|
5023
4809
|
const askJob = (jobSummary) => askContext(buildUiContext({ sessionId, pageSessionId, workspace: snapshot.workspace.id, job: jobSummary.name, detail: void 0, jobSummary }), t("suggestedQuestion2"));
|
|
5024
|
-
return /* @__PURE__ */ import_react5.default.createElement(HarborSessionContext.Provider, { value: sessionId }, /* @__PURE__ */ import_react5.default.createElement("main", { ref: rootNode, className: "hse-root" }, /* @__PURE__ */ import_react5.default.createElement("div", { className: "hse-page hse-layout" },
|
|
4810
|
+
return /* @__PURE__ */ import_react5.default.createElement(HarborSessionContext.Provider, { value: sessionId }, /* @__PURE__ */ import_react5.default.createElement("main", { ref: rootNode, className: "hse-root" }, /* @__PURE__ */ import_react5.default.createElement("div", { className: "hse-page hse-layout" }, /* @__PURE__ */ import_react5.default.createElement("div", { className: "hse-main-panel" }, ui.error ? /* @__PURE__ */ import_react5.default.createElement(HarborErrorState, { error: ui.error, title: t("contextBindFailed"), t }) : null, /* @__PURE__ */ import_react5.default.createElement(OperationTray, { hideWhenEmpty: true, ...{ sessionId, request, update }, scopeKey: snapshot?.workspace?.id ?? workspace, t: (key) => t(`operationTray_${key}`), onViewResult: viewDiagnostic }), selected ? /* @__PURE__ */ import_react5.default.createElement(Workbench, { key: `${selected.workspace}\0${selected.job}`, job: selected.job, workspace: selected.workspace, jobs: snapshot?.jobs ?? [], close: closeWorkbench, navigation: selected.navigation, consumeNavigation, restoreView: selected.restoreView, hasHistory: selected.fromNavigation, scrollContainerRef: scrollNode, onViewStateChange: (value) => {
|
|
5025
4811
|
activeWorkbenchView.current = value;
|
|
5026
4812
|
}, sessionId, pageSessionId, bridge, askContext, t }) : /* @__PURE__ */ import_react5.default.createElement(import_react5.default.Fragment, null, historyDepth ? /* @__PURE__ */ import_react5.default.createElement("button", { type: "button", className: "hse-button hse-dashboard-back", onClick: closeWorkbench }, t("back")) : null, snapshot ? /* @__PURE__ */ import_react5.default.createElement(GettingStarted, { jobs: snapshot.jobs, openJob, t }) : null, /* @__PURE__ */ import_react5.default.createElement("section", { className: "hse-health-summary" }, /* @__PURE__ */ import_react5.default.createElement("div", { className: "hse-head" }, /* @__PURE__ */ import_react5.default.createElement("div", null, /* @__PURE__ */ import_react5.default.createElement("small", null, "Harbor \xB7 ", t("eyebrow")), /* @__PURE__ */ import_react5.default.createElement("h1", null, t("health"), ": ", t((snapshot?.overview?.attention?.blocked ?? 0) > 0 ? "health_blocked" : ["blocked", "stalled", "infrastructure", "invalid", "regressed", "gate", "fresh-baseline"].some((key) => (snapshot?.overview?.attention?.[key] ?? 0) > 0) ? "healthRisk" : "healthy")), /* @__PURE__ */ import_react5.default.createElement("p", null, t("attentionCountHint"))), /* @__PURE__ */ import_react5.default.createElement("button", { type: "button", className: "hse-button", onClick: () => void state.load() }, t("refresh"))), /* @__PURE__ */ import_react5.default.createElement("div", { className: "hse-health-filters", "aria-label": t("attention") }, ATTENTION_FILTERS.map((filter) => /* @__PURE__ */ import_react5.default.createElement("button", { type: "button", key: filter, "aria-pressed": attentionFilter === filter, onClick: () => {
|
|
5027
4813
|
setAttentionFilter(filter);
|
|
@@ -5083,12 +4869,16 @@ function decodeToolResult(block) {
|
|
|
5083
4869
|
return void 0;
|
|
5084
4870
|
}
|
|
5085
4871
|
}
|
|
5086
|
-
function HarborToolView({ block, toolName, bridge, sessionId, t }) {
|
|
4872
|
+
function HarborToolView({ block, toolName, bridge, sessionId, prepareQuestion, t }) {
|
|
5087
4873
|
const [open, setOpen] = (0, import_react5.useState)(false);
|
|
5088
|
-
const
|
|
4874
|
+
const [navigationNotice, setNavigationNotice] = (0, import_react5.useState)("");
|
|
4875
|
+
const settled = block?.kind === "tool-result";
|
|
4876
|
+
const value = settled ? decodeToolResult(block) : void 0;
|
|
5089
4877
|
const uiAction = trustedHarborUiAction(toolName, value);
|
|
5090
|
-
const
|
|
5091
|
-
|
|
4878
|
+
const draft = toolName === "harbor_propose_action" && value?.schema === "harbor-action-draft/v1" && typeof value.draftId === "string" && value.draftId ? value : void 0;
|
|
4879
|
+
const onNavigate = (accepted) => setNavigationNotice(t(accepted === false ? "navigationPending" : "preparedInHarbor"));
|
|
4880
|
+
const actions = createHarborActionHandlers({ bridge, sessionId, prepareQuestion, onNavigate, t });
|
|
4881
|
+
return /* @__PURE__ */ import_react5.default.createElement(HarborSessionContext.Provider, { value: sessionId }, /* @__PURE__ */ import_react5.default.createElement("section", { className: "hse-tool" }, /* @__PURE__ */ import_react5.default.createElement("button", { type: "button", onClick: () => setOpen(!open) }, /* @__PURE__ */ import_react5.default.createElement("strong", null, "\u{1F433} ", toolName), /* @__PURE__ */ import_react5.default.createElement("small", null, !settled ? "running" : block.isError ? "error" : "\u2713")), open ? /* @__PURE__ */ import_react5.default.createElement("pre", null, value ? pretty2(value) : blockText(block) || "Running\u2026") : null, uiAction ? /* @__PURE__ */ import_react5.default.createElement("button", { type: "button", className: "hse-tool-action", onClick: () => onNavigate(bridge.navigate(sessionId, uiAction, { force: true })) }, t("viewInHarbor")) : null, draft ? /* @__PURE__ */ import_react5.default.createElement(ActionDraftCard, { draft, onSourceDraft: actions.openSourceDraft, onReprepare: actions.reprepare, onViewComparison: actions.viewComparison, onViewResult: (result) => actions.viewDiagnostic(draft, result), t }) : null, navigationNotice ? /* @__PURE__ */ import_react5.default.createElement("p", { className: "hse-draft-notice", role: "status" }, navigationNotice) : null));
|
|
5092
4882
|
}
|
|
5093
4883
|
var name = "dsh-harbor-evolution";
|
|
5094
4884
|
var inject = ["slots", "locale", "inputTriggers", "sessions", "conversation"];
|
|
@@ -5107,6 +4897,21 @@ function apply(ctx) {
|
|
|
5107
4897
|
const injected = (sessionId) => ({
|
|
5108
4898
|
t,
|
|
5109
4899
|
bridge,
|
|
4900
|
+
prepareQuestion: async (context, prompt = "") => {
|
|
4901
|
+
const { actx, conversation } = scopedConversation(sessionId);
|
|
4902
|
+
if (!actx || !conversation?.input?.for || !context) return false;
|
|
4903
|
+
let input;
|
|
4904
|
+
try {
|
|
4905
|
+
input = conversation.input.for(actx);
|
|
4906
|
+
const issued = await bridge.issue(sessionId, context, { forceNew: true });
|
|
4907
|
+
return commitIssuedDraft(bridge, sessionId, issued, (reference, text) => replaceStructuredHarborReference(input, reference, text), prompt, input.state.getSnapshot().phase, true);
|
|
4908
|
+
} catch (error) {
|
|
4909
|
+
const failure2 = normalizeHarborUiError(error);
|
|
4910
|
+
bridge.update(sessionId, { status: "error", error: failure2 });
|
|
4911
|
+
input?.notify?.("error", failure2.message);
|
|
4912
|
+
return false;
|
|
4913
|
+
}
|
|
4914
|
+
},
|
|
5110
4915
|
replaceHarborReference: (issued, prompt) => {
|
|
5111
4916
|
const { actx, conversation } = scopedConversation(sessionId);
|
|
5112
4917
|
if (!actx || !conversation?.input?.for) return false;
|
|
@@ -5131,13 +4936,13 @@ function apply(ctx) {
|
|
|
5131
4936
|
}
|
|
5132
4937
|
});
|
|
5133
4938
|
ctx.slots.inject("conversation.view", () => ctx.slots.register({ name: "conversation.view", id: "harbor-evolution", order: 30, locale: NS, label: () => t("tab"), inject: injected }, DashboardView));
|
|
5134
|
-
ctx.slots.inject("conversation.input.dock", () => ctx.slots.register({ name: "conversation.input.dock", id: "harbor-evolution-
|
|
4939
|
+
ctx.slots.inject("conversation.input.dock", () => ctx.slots.register({ name: "conversation.input.dock", id: "harbor-evolution-input-sync", order: 10, locale: NS, inject: injected }, HarborInputSync));
|
|
5135
4940
|
ctx.slots.inject("settings.section", () => ctx.slots.register({ name: "settings.section", id: "harbor-evolution", order: 35, label: () => t("settings"), inject: () => ({ t }) }, DoctorView));
|
|
5136
4941
|
ctx.slots.inject("tool.call.toolview", function* registerTools() {
|
|
5137
4942
|
for (const key of ["harbor_candidate_snapshot", "harbor_model_binding", "harbor_evolution_init", "harbor_evolution_doctor", "harbor_quick_diagnostic_init", "harbor_session_diagnostic_preview", "harbor_session_diagnostic_run", "harbor_dataset_validate", "harbor_context_preview", "harbor_eval_run", "harbor_eval_result", "harbor_evaluator_inspect", "harbor_evaluator_update", "harbor_ground_truth_init", "harbor_evaluator_meta_evaluate", "harbor_candidate_compare", "harbor_resolve_page_context", "harbor_get_evidence", "harbor_propose_action"]) yield ctx.slots.register({ name: "tool.call.toolview", key, inject: injected }, HarborToolView);
|
|
5138
4943
|
});
|
|
5139
4944
|
}
|
|
5140
|
-
module.exports = { name, inject, apply,
|
|
4945
|
+
module.exports = { name, inject, apply, HarborInputSync, HarborToolView, createHarborActionHandlers, actionDraftContext, resolvedUiContext, harborDisplayedAnswerBasis, recoverHarborTurn, applySourceProposal, removeContextPart, mergeHarborFocus, selectedSourceLines, sectionForNavigation, HarborUiBridge, buildUiContext, harborContextFilters, replaceStructuredHarborReference, clearStructuredHarborReferences, needsStructuredHarborNormalization, commitIssuedDraft, isHarborInputBusy, dashboardFailureState, workbenchSuccessState, workbenchFailureState, harborTurnProjection, harborSubmissionTransition, effectiveHarborSubmissionReference, shouldClearObservedExplicit, isExplicitContextExpired, evidenceCriterionOwners, evidenceFocusKey, isEvidenceFocused, trialNavigationView, trialRestoreView, navigationHistoryEntry, ownsNavigationHistoryEntry, restoreNavigationSelection, clearConsumedNavigation, ownsTrialRequest, trialListSuccessState, trialListFailureState, hasTrialFilters, trialDetailLoadingState, trialDetailErrorState, comparisonCandidates, governanceRequestKey, ownsGovernanceRequest, ownsGovernanceBinding, normalizeHarborUiError, harborApiError, trustedHarborUiAction, trustedHarborResolvedContext, trustedHarborReferences, harborAnswerBasis, toolUiAction };
|
|
5141
4946
|
return module.exports;
|
|
5142
4947
|
},
|
|
5143
4948
|
});
|