@sireai/optimus 0.1.5 → 0.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/README.md +8 -1
  2. package/dist/cli/optimus.js +98 -86
  3. package/dist/cli/optimus.js.map +1 -1
  4. package/dist/cli/self-update.js +19 -4
  5. package/dist/cli/self-update.js.map +1 -1
  6. package/dist/config/load-config.js +9 -46
  7. package/dist/config/load-config.js.map +1 -1
  8. package/dist/integrations/jira/jira-auth-refresh.d.ts +15 -0
  9. package/dist/integrations/jira/jira-auth-refresh.js +131 -0
  10. package/dist/integrations/jira/jira-auth-refresh.js.map +1 -0
  11. package/dist/integrations/jira/jira-cli.js +102 -19
  12. package/dist/integrations/jira/jira-cli.js.map +1 -1
  13. package/dist/integrations/jira/jira-client.d.ts +6 -11
  14. package/dist/integrations/jira/jira-client.js +105 -271
  15. package/dist/integrations/jira/jira-client.js.map +1 -1
  16. package/dist/problem-solving-core/codex/codex-runner.d.ts +4 -0
  17. package/dist/problem-solving-core/codex/codex-runner.js +49 -3
  18. package/dist/problem-solving-core/codex/codex-runner.js.map +1 -1
  19. package/dist/task-environment/delivery/feishu-card-renderer.js +9 -0
  20. package/dist/task-environment/delivery/feishu-card-renderer.js.map +1 -1
  21. package/dist/task-environment/delivery/feishu-content/feishu-content-renderer.d.ts +1 -0
  22. package/dist/task-environment/delivery/feishu-content/feishu-content-renderer.js +5 -0
  23. package/dist/task-environment/delivery/feishu-content/feishu-content-renderer.js.map +1 -1
  24. package/dist/task-environment/delivery/feishu-notifier.js +1 -0
  25. package/dist/task-environment/delivery/feishu-notifier.js.map +1 -1
  26. package/dist/task-environment/delivery/feishu-templates/analysis-message-template.js +4 -0
  27. package/dist/task-environment/delivery/feishu-templates/analysis-message-template.js.map +1 -1
  28. package/dist/task-environment/delivery/feishu-templates/bugfix-message-template.js +4 -0
  29. package/dist/task-environment/delivery/feishu-templates/bugfix-message-template.js.map +1 -1
  30. package/dist/task-environment/delivery/feishu-templates/default-message-template.js +4 -0
  31. package/dist/task-environment/delivery/feishu-templates/default-message-template.js.map +1 -1
  32. package/dist/task-environment/delivery/feishu-templates/patch-message-template.js +4 -0
  33. package/dist/task-environment/delivery/feishu-templates/patch-message-template.js.map +1 -1
  34. package/dist/task-environment/delivery/feishu-templates/sentry-bugfix-message-template.js +4 -0
  35. package/dist/task-environment/delivery/feishu-templates/sentry-bugfix-message-template.js.map +1 -1
  36. package/dist/task-environment/delivery/feishu-templates/template-types.d.ts +1 -0
  37. package/dist/task-environment/delivery/sentry-feishu-card-renderer.js +5 -0
  38. package/dist/task-environment/delivery/sentry-feishu-card-renderer.js.map +1 -1
  39. package/dist/task-environment/delivery/task-delivery-service.js +4 -1
  40. package/dist/task-environment/delivery/task-delivery-service.js.map +1 -1
  41. package/dist/task-environment/delivery/task-publication-service.d.ts +3 -8
  42. package/dist/task-environment/delivery/task-publication-service.js +0 -43
  43. package/dist/task-environment/delivery/task-publication-service.js.map +1 -1
  44. package/dist/task-environment/execution-addresses.d.ts +1 -0
  45. package/dist/task-environment/execution-addresses.js +82 -1
  46. package/dist/task-environment/execution-addresses.js.map +1 -1
  47. package/dist/task-environment/observability/execution-metrics.d.ts +11 -0
  48. package/dist/task-environment/observability/execution-metrics.js +110 -0
  49. package/dist/task-environment/observability/execution-metrics.js.map +1 -0
  50. package/dist/task-environment/observability/runtime-panel.d.ts +1 -0
  51. package/dist/task-environment/observability/runtime-panel.js +32 -2
  52. package/dist/task-environment/observability/runtime-panel.js.map +1 -1
  53. package/dist/task-environment/storage/sqlite-task-store.d.ts +5 -1
  54. package/dist/task-environment/storage/sqlite-task-store.js +65 -6
  55. package/dist/task-environment/storage/sqlite-task-store.js.map +1 -1
  56. package/dist/types.d.ts +17 -7
  57. package/package.json +4 -2
package/README.md CHANGED
@@ -20,7 +20,13 @@ From a user view, the flow is simple: submit a problem, let Optimus run inside t
20
20
  ### 1. Install
21
21
 
22
22
  ```bash
23
- npm install -g @sireai/optimus
23
+ npm install -g @sireai/optimus --registry=https://registry.npmjs.org
24
+ ```
25
+
26
+ If Jira CAS refresh reports a missing Playwright browser, install Chromium once:
27
+
28
+ ```bash
29
+ npx playwright install chromium
24
30
  ```
25
31
 
26
32
  ### 2. Run setup
@@ -95,6 +101,7 @@ Jira intake:
95
101
 
96
102
  ```bash
97
103
  optimus jira-submit-issue --issue-key MICARAPPI-13178 --repo mobile-app
104
+ optimus jira-refresh-auth --issue-key MICARAPPI-13178
98
105
  ```
99
106
 
100
107
  Sentry intake:
@@ -23,6 +23,7 @@ import { TriageRunner } from "../task-environment/orchestration/triage-runner.js
23
23
  import { OptimusRuntime } from "../task-environment/runtime/optimus-runtime.js";
24
24
  import { SQLiteTaskStore } from "../task-environment/storage/sqlite-task-store.js";
25
25
  import { SQLiteEventStore } from "../task-environment/storage/sqlite-event-store.js";
26
+ import { buildTaskExecutionMetrics, formatExecutionMetricsCompact } from "../task-environment/observability/execution-metrics.js";
26
27
  import { FeishuNotifier } from "../task-environment/delivery/feishu-notifier.js";
27
28
  import { TaskDeliveryDispatcher } from "../task-environment/delivery/task-delivery-dispatcher.js";
28
29
  import { TaskDeliveryService } from "../task-environment/delivery/task-delivery-service.js";
@@ -164,7 +165,7 @@ function renderCliHelp() {
164
165
  " postrun-retry Rebuild postrun artifacts and optionally replay publication",
165
166
  "",
166
167
  "Integration commands:",
167
- " jira-search|jira-get-issue|jira-search-assigned-open|jira-submit-issue|jira-submit-assigned-open|jira-add-comment|jira-poll-once|jira-poll-daemon",
168
+ " jira-search|jira-get-issue|jira-search-assigned-open|jira-submit-issue|jira-submit-assigned-open|jira-add-comment|jira-refresh-auth|jira-poll-once|jira-poll-daemon",
168
169
  " sentry-get-event|sentry-submit-event",
169
170
  " Example: optimus help jira-submit-issue",
170
171
  "",
@@ -362,7 +363,8 @@ function renderCommandHelp(command) {
362
363
  " --expand <csv> Jira expand parameters",
363
364
  " --properties <csv> Jira properties",
364
365
  " --comment-limit <n> Comment limit, default 3",
365
- " --update-history true|false Include update history"
366
+ " --update-history true|false Include update history",
367
+ " --raw Include raw Jira REST response"
366
368
  ].join("\n"),
367
369
  "jira-search": [
368
370
  "optimus jira-search",
@@ -402,6 +404,19 @@ function renderCommandHelp(command) {
402
404
  " --issue-key <key> Jira issue key",
403
405
  " --body <text> Comment body"
404
406
  ].join("\n"),
407
+ "jira-refresh-auth": [
408
+ "optimus jira-refresh-auth",
409
+ "",
410
+ "Usage:",
411
+ " optimus jira-refresh-auth [options]",
412
+ "",
413
+ "Optional:",
414
+ " --verify Verify current Jira REST auth without refreshing",
415
+ " --issue-key <key> Verify by reading a specific Jira issue",
416
+ "",
417
+ "Example:",
418
+ " optimus jira-refresh-auth --issue-key MICARAPPI-13178"
419
+ ].join("\n"),
405
420
  "jira-poll-once": [
406
421
  "optimus jira-poll-once",
407
422
  "",
@@ -475,6 +490,8 @@ function mapJiraCommand(command) {
475
490
  return "submit-assigned-open";
476
491
  case "jira-add-comment":
477
492
  return "add-comment";
493
+ case "jira-refresh-auth":
494
+ return "refresh-auth";
478
495
  case "jira-poll-once":
479
496
  return "poll-once";
480
497
  case "jira-poll-daemon":
@@ -502,44 +519,18 @@ function resolveJiraQuickDoctorIssues(config, options) {
502
519
  fix: "Rerun `optimus setup` and provide a real Jira base URL."
503
520
  });
504
521
  }
505
- if (config.authType === "bearer") {
506
- if (!config.bearerToken?.trim()) {
507
- issues.push({
508
- code: "jira_token_missing",
509
- message: "Jira integration is enabled, but Jira bearer token is missing.",
510
- fix: "Rerun `optimus setup` and provide a Jira token."
511
- });
512
- }
513
- return issues;
514
- }
515
- if (config.authType === "basic") {
516
- if (!config.username?.trim() || !(config.apiToken?.trim() || config.password?.trim())) {
517
- issues.push({
518
- code: "jira_basic_auth_missing",
519
- message: "Jira integration is enabled, but Jira basic auth credentials are incomplete.",
520
- fix: "Provide Jira username plus api token or password, then rerun `optimus doctor --quick`."
521
- });
522
- }
523
- return issues;
524
- }
525
- if (!config.mcpUrl?.trim() || /jira-mcp\.example\.com/i.test(config.mcpUrl)) {
522
+ if (!config.personalToken?.trim()) {
526
523
  issues.push({
527
- code: "jira_mcp_url_missing",
528
- message: "Jira integration is enabled, but Jira MCP URL is missing or still using the placeholder value.",
529
- fix: "Provide a real Jira MCP URL, then rerun `optimus doctor --quick`."
524
+ code: "jira_token_missing",
525
+ message: "Jira integration is enabled, but Jira personal token is missing.",
526
+ fix: "Rerun `optimus setup` and provide a Jira personal token."
530
527
  });
531
528
  }
532
- const requiredHeaders = [
533
- "X-Atlassian-Jira-Url",
534
- "X-Atlassian-Username",
535
- "X-Atlassian-Jira-Personal-Token"
536
- ];
537
- const missingHeaders = requiredHeaders.filter((name) => !config.httpHeaders[name]?.trim());
538
- if (missingHeaders.length > 0) {
529
+ if (!config.casCookieName?.trim()) {
539
530
  issues.push({
540
- code: "jira_mcp_headers_missing",
541
- message: `Jira integration is enabled, but Jira MCP headers are incomplete: ${missingHeaders.join(", ")}.`,
542
- fix: "Provide the required Jira MCP headers, then rerun `optimus doctor --quick`."
531
+ code: "jira_cas_cookie_name_missing",
532
+ message: "Jira integration is enabled, but Jira CAS cookie name is missing.",
533
+ fix: "Rerun `optimus setup` and provide the Jira CAS cookie name."
543
534
  });
544
535
  }
545
536
  return issues;
@@ -924,12 +915,24 @@ async function promptSetupAnswers(defaults) {
924
915
  }
925
916
  return rl.question(prompt);
926
917
  };
918
+ const printSetupSection = (title, detail) => {
919
+ console.log(`\n[${title}]`);
920
+ if (detail) {
921
+ console.log(detail);
922
+ }
923
+ };
924
+ const renderSetupPrompt = (label, promptLabel, defaultValue) => {
925
+ const suffix = defaultValue !== undefined ? ` [${defaultValue}]` : "";
926
+ return `[${label}] ${promptLabel}${suffix}: `;
927
+ };
927
928
  try {
928
929
  if (await pathExists(configPath)) {
929
930
  console.log(`Existing config found at ${configPath}. Press Enter to keep current values.`);
930
931
  }
931
- const repoPath = (await ask(`Repository path [${defaults.repoPath}]: `)).trim() || defaults.repoPath;
932
- const repoAlias = (await ask(`Repository alias [${defaults.repoAlias}]: `)).trim() || defaults.repoAlias;
932
+ printSetupSection("Repository", "Register the primary local repository used by Optimus.");
933
+ const repoPath = (await ask(renderSetupPrompt("Required", "Repository path", defaults.repoPath))).trim() || defaults.repoPath;
934
+ const repoAlias = (await ask(renderSetupPrompt("Required", "Repository alias", defaults.repoAlias))).trim() || defaults.repoAlias;
935
+ printSetupSection("Codex", "Choose one authentication mode, then fill the fields that follow.");
933
936
  const codexAuthMode = await askSetupCodexAuthMode({ ask, defaultMode: defaults.codexAuthMode });
934
937
  let codexApiKey;
935
938
  let codexProviderId;
@@ -937,54 +940,54 @@ async function promptSetupAnswers(defaults) {
937
940
  let codexProviderBaseUrl;
938
941
  let codexProviderApiKeyEnvName;
939
942
  if (codexAuthMode === "openai_api_key") {
940
- codexApiKey = (await ask("OpenAI API key for OPENAI_API_KEY (leave blank to keep existing): ")).trim() || undefined;
943
+ codexApiKey = (await ask(renderSetupPrompt("Optional", "OpenAI API key for OPENAI_API_KEY", "leave blank to keep existing"))).trim() || undefined;
941
944
  }
942
945
  else if (codexAuthMode === "model_provider") {
943
- codexProviderId = (await ask(`Provider id [${defaults.codexProviderId ?? ""}]: `)).trim() || defaults.codexProviderId;
944
- codexProviderDisplayName = (await ask(`Provider display name [${defaults.codexProviderDisplayName ?? ""}]: `)).trim() || defaults.codexProviderDisplayName;
945
- codexProviderBaseUrl = (await ask(`Provider base URL [${defaults.codexProviderBaseUrl ?? ""}]: `)).trim() || defaults.codexProviderBaseUrl;
946
- codexProviderApiKeyEnvName = (await ask(`Provider API key env name [${defaults.codexProviderApiKeyEnvName ?? ""}]: `)).trim() || defaults.codexProviderApiKeyEnvName;
946
+ codexProviderId = (await ask(renderSetupPrompt("Required", "Provider id", defaults.codexProviderId ?? ""))).trim() || defaults.codexProviderId;
947
+ codexProviderDisplayName = (await ask(renderSetupPrompt("Required", "Provider display name", defaults.codexProviderDisplayName ?? ""))).trim() || defaults.codexProviderDisplayName;
948
+ codexProviderBaseUrl = (await ask(renderSetupPrompt("Required", "Provider base URL", defaults.codexProviderBaseUrl ?? ""))).trim() || defaults.codexProviderBaseUrl;
949
+ codexProviderApiKeyEnvName = (await ask(renderSetupPrompt("Required", "Provider API key env name", defaults.codexProviderApiKeyEnvName ?? ""))).trim() || defaults.codexProviderApiKeyEnvName;
947
950
  const providerKeyLabel = codexProviderApiKeyEnvName || defaults.codexProviderApiKeyEnvName || "the configured provider env";
948
- codexApiKey = (await ask(`Provider API key value for ${providerKeyLabel} (leave blank to keep existing): `)).trim() || undefined;
951
+ codexApiKey = (await ask(renderSetupPrompt("Optional", `Provider API key value for ${providerKeyLabel}`, "leave blank to keep existing"))).trim() || undefined;
949
952
  }
950
- const enableFeishuInput = (await ask(`Enable Feishu delivery? [${defaults.enableFeishu ? "Y/n" : "y/N"}] `)).trim().toLowerCase();
953
+ printSetupSection("Feishu", "Enable this module when task notifications should be sent to Feishu.");
954
+ const enableFeishuInput = (await ask(renderSetupPrompt("Optional module", "Enable Feishu delivery", defaults.enableFeishu ? "Y/n" : "y/N"))).trim().toLowerCase();
951
955
  const enableFeishu = enableFeishuInput.length === 0
952
956
  ? defaults.enableFeishu
953
957
  : ["y", "yes"].includes(enableFeishuInput);
954
958
  const feishuWebhook = enableFeishu
955
- ? (await ask(`Feishu webhook [${defaults.feishuWebhook ? "configured" : ""}]: `)).trim() || defaults.feishuWebhook
959
+ ? (await ask(renderSetupPrompt("Required", "Feishu webhook", defaults.feishuWebhook ? "configured" : ""))).trim() || defaults.feishuWebhook
956
960
  : undefined;
957
961
  const feishuSecret = enableFeishu
958
- ? (await ask(`Feishu secret (optional) [${defaults.feishuSecret ? "configured" : ""}]: `)).trim() || defaults.feishuSecret
962
+ ? (await ask(renderSetupPrompt("Optional", "Feishu secret", defaults.feishuSecret ? "configured" : ""))).trim() || defaults.feishuSecret
959
963
  : undefined;
960
- const enableJiraInput = (await ask(`Enable Jira integration? [${defaults.enableJira ? "Y/n" : "y/N"}] `)).trim().toLowerCase();
964
+ printSetupSection("Jira", "Enable this module when Optimus should read issues or comment back to Jira.");
965
+ const enableJiraInput = (await ask(renderSetupPrompt("Optional module", "Enable Jira integration", defaults.enableJira ? "Y/n" : "y/N"))).trim().toLowerCase();
961
966
  const enableJira = enableJiraInput.length === 0
962
967
  ? defaults.enableJira
963
968
  : ["y", "yes"].includes(enableJiraInput);
964
969
  const jiraBaseUrl = enableJira
965
- ? (await ask(`Jira base URL [${defaults.jiraBaseUrl ?? ""}]: `)).trim() || defaults.jiraBaseUrl
966
- : undefined;
967
- const jiraMcpUrl = enableJira
968
- ? (await ask(`Jira MCP URL [${defaults.jiraMcpUrl ?? ""}]: `)).trim() || defaults.jiraMcpUrl
969
- : undefined;
970
- const jiraUsername = enableJira
971
- ? (await ask(`Jira username [${defaults.jiraUsername ?? ""}]: `)).trim() || defaults.jiraUsername
970
+ ? (await ask(renderSetupPrompt("Required", "Jira base URL", defaults.jiraBaseUrl ?? ""))).trim() || defaults.jiraBaseUrl
972
971
  : undefined;
973
972
  const jiraPersonalToken = enableJira
974
- ? (await ask(`Jira personal token [${defaults.jiraPersonalToken ? "configured" : ""}]: `)).trim() || defaults.jiraPersonalToken
973
+ ? (await ask(renderSetupPrompt("Required", "Jira personal token", defaults.jiraPersonalToken ? "configured" : ""))).trim() || defaults.jiraPersonalToken
974
+ : undefined;
975
+ const jiraCasCookieName = enableJira
976
+ ? (await ask(renderSetupPrompt("Optional", "Jira CAS cookie name", defaults.jiraCasCookieName ?? "_aegis_cas_p"))).trim() || defaults.jiraCasCookieName || "_aegis_cas_p"
975
977
  : undefined;
976
- const enableSentryInput = (await ask(`Enable Sentry integration? [${defaults.enableSentry ? "Y/n" : "y/N"}] `)).trim().toLowerCase();
978
+ printSetupSection("Sentry", "Enable this module when tasks can be created from Sentry events.");
979
+ const enableSentryInput = (await ask(renderSetupPrompt("Optional module", "Enable Sentry integration", defaults.enableSentry ? "Y/n" : "y/N"))).trim().toLowerCase();
977
980
  const enableSentry = enableSentryInput.length === 0
978
981
  ? defaults.enableSentry
979
982
  : ["y", "yes"].includes(enableSentryInput);
980
983
  const sentryBaseUrl = enableSentry
981
- ? (await ask(`Sentry base URL [${defaults.sentryBaseUrl ?? ""}]: `)).trim() || defaults.sentryBaseUrl
984
+ ? (await ask(renderSetupPrompt("Required", "Sentry base URL", defaults.sentryBaseUrl ?? ""))).trim() || defaults.sentryBaseUrl
982
985
  : undefined;
983
986
  const sentryOrg = enableSentry
984
- ? (await ask(`Sentry org [${defaults.sentryOrg ?? ""}]: `)).trim() || defaults.sentryOrg
987
+ ? (await ask(renderSetupPrompt("Required", "Sentry org", defaults.sentryOrg ?? ""))).trim() || defaults.sentryOrg
985
988
  : undefined;
986
989
  const sentryAuthToken = enableSentry
987
- ? (await ask(`Sentry auth token [${defaults.sentryAuthToken ? "configured" : ""}]: `)).trim() || defaults.sentryAuthToken
990
+ ? (await ask(renderSetupPrompt("Required", "Sentry auth token", defaults.sentryAuthToken ? "configured" : ""))).trim() || defaults.sentryAuthToken
988
991
  : undefined;
989
992
  return {
990
993
  repoPath,
@@ -1000,9 +1003,9 @@ async function promptSetupAnswers(defaults) {
1000
1003
  ...(feishuSecret ? { feishuSecret } : {}),
1001
1004
  enableJira,
1002
1005
  ...(jiraBaseUrl ? { jiraBaseUrl } : {}),
1003
- ...(jiraMcpUrl ? { jiraMcpUrl } : {}),
1004
- ...(jiraUsername ? { jiraUsername } : {}),
1005
1006
  ...(jiraPersonalToken ? { jiraPersonalToken } : {}),
1007
+ ...(jiraCasCookieName ? { jiraCasCookieName } : {}),
1008
+ ...(defaults.jiraCustomHeaders ? { jiraCustomHeaders: defaults.jiraCustomHeaders } : {}),
1006
1009
  enableSentry,
1007
1010
  ...(sentryBaseUrl ? { sentryBaseUrl } : {}),
1008
1011
  ...(sentryOrg ? { sentryOrg } : {}),
@@ -1052,9 +1055,9 @@ async function resolveDefaultSetupAnswers() {
1052
1055
  ...(config.delivery.feishu.secret ? { feishuSecret: config.delivery.feishu.secret } : {}),
1053
1056
  enableJira: config.jira.enabled,
1054
1057
  ...(config.jira.baseUrl ? { jiraBaseUrl: config.jira.baseUrl } : {}),
1055
- ...(config.jira.mcpUrl ? { jiraMcpUrl: config.jira.mcpUrl } : {}),
1056
- ...(config.jira.httpHeaders["X-Atlassian-Username"] ? { jiraUsername: config.jira.httpHeaders["X-Atlassian-Username"] } : {}),
1057
- ...(config.jira.httpHeaders["X-Atlassian-Jira-Personal-Token"] ? { jiraPersonalToken: config.jira.httpHeaders["X-Atlassian-Jira-Personal-Token"] } : {}),
1058
+ ...(config.jira.personalToken ? { jiraPersonalToken: config.jira.personalToken } : {}),
1059
+ ...(config.jira.casCookieName ? { jiraCasCookieName: config.jira.casCookieName } : {}),
1060
+ ...(config.jira.customHeaders ? { jiraCustomHeaders: config.jira.customHeaders } : {}),
1058
1061
  enableSentry: config.sentry.enabled,
1059
1062
  ...(config.sentry.baseUrl ? { sentryBaseUrl: config.sentry.baseUrl } : {}),
1060
1063
  ...(config.sentry.org ? { sentryOrg: config.sentry.org } : {}),
@@ -1079,7 +1082,7 @@ function normalizeSetupCodexAuthMode(value) {
1079
1082
  }
1080
1083
  function renderSetupCodexAuthModePrompt(defaultMode) {
1081
1084
  const defaultIndex = SETUP_CODEX_AUTH_MODE_OPTIONS.find((option) => option.mode === defaultMode)?.index ?? "1";
1082
- const lines = ["Codex auth mode:"];
1085
+ const lines = ["[Required] Codex auth mode:"];
1083
1086
  for (const option of SETUP_CODEX_AUTH_MODE_OPTIONS) {
1084
1087
  const defaultSuffix = option.index === defaultIndex ? " (default)" : "";
1085
1088
  lines.push(`${option.index}. ${option.label} [${option.mode}]${defaultSuffix}`);
@@ -1125,12 +1128,6 @@ function validateSetupAnswers(answers) {
1125
1128
  if (answers.enableJira && !answers.jiraBaseUrl?.trim()) {
1126
1129
  return "setup requires a Jira base URL when Jira integration is enabled.";
1127
1130
  }
1128
- if (answers.enableJira && !answers.jiraMcpUrl?.trim()) {
1129
- return "setup requires a Jira MCP URL when Jira integration is enabled.";
1130
- }
1131
- if (answers.enableJira && !answers.jiraUsername?.trim()) {
1132
- return "setup requires a Jira username when Jira integration is enabled.";
1133
- }
1134
1131
  if (answers.enableJira && !answers.jiraPersonalToken?.trim()) {
1135
1132
  return "setup requires a Jira personal token when Jira integration is enabled.";
1136
1133
  }
@@ -1207,19 +1204,16 @@ function buildSetupConfig(answers) {
1207
1204
  config.jira.enabled = answers.enableJira;
1208
1205
  if (answers.enableJira) {
1209
1206
  config.jira.baseUrl = answers.jiraBaseUrl ?? config.jira.baseUrl;
1210
- if (answers.jiraMcpUrl) {
1211
- config.jira.mcpUrl = answers.jiraMcpUrl;
1212
- }
1213
- config.jira.authType = "http_headers";
1214
- config.jira.httpHeaders = {
1215
- "X-Atlassian-Jira-Url": answers.jiraBaseUrl ?? config.jira.baseUrl,
1216
- "X-Atlassian-Username": answers.jiraUsername ?? "",
1217
- "X-Atlassian-Jira-Personal-Token": answers.jiraPersonalToken ?? ""
1218
- };
1219
- delete config.jira.bearerToken;
1220
- delete config.jira.username;
1221
- delete config.jira.apiToken;
1222
- delete config.jira.password;
1207
+ if (answers.jiraPersonalToken) {
1208
+ config.jira.personalToken = answers.jiraPersonalToken;
1209
+ }
1210
+ config.jira.casCookieName = answers.jiraCasCookieName?.trim() || "_aegis_cas_p";
1211
+ if (answers.jiraCustomHeaders?.trim()) {
1212
+ config.jira.customHeaders = answers.jiraCustomHeaders.trim();
1213
+ }
1214
+ else {
1215
+ delete config.jira.customHeaders;
1216
+ }
1223
1217
  }
1224
1218
  config.sentry.enabled = answers.enableSentry;
1225
1219
  if (answers.enableSentry) {
@@ -2389,6 +2383,7 @@ async function main() {
2389
2383
  const taskRuns = runs.filter((run) => run.taskId === task.taskId);
2390
2384
  const activeRun = runs.find((run) => run.runId === task.activeRunId) ?? taskRuns.slice(-1)[0];
2391
2385
  const timing = activeRun ? buildRunTimingSnapshot(activeRun, config) : { elapsedMs: 0, idleMs: 0, timeoutKind: null };
2386
+ const activeMetrics = activeRun ? buildTaskExecutionMetrics(activeRun) : undefined;
2392
2387
  return {
2393
2388
  taskId: task.taskId,
2394
2389
  taskPackageId: task.taskPackageId,
@@ -2415,9 +2410,14 @@ async function main() {
2415
2410
  elapsedMs: activeRun ? timing.elapsedMs : null,
2416
2411
  idleMs: activeRun ? timing.idleMs : null,
2417
2412
  timeoutKind: activeRun ? timing.timeoutKind : null,
2413
+ metrics: activeMetrics ? {
2414
+ ...activeMetrics,
2415
+ display: formatExecutionMetricsCompact(activeMetrics)
2416
+ } : null,
2418
2417
  nextAction: buildTaskNextAction(task.status, activeRun?.failureCategory),
2419
2418
  runs: taskRuns.slice(-3).map((run) => {
2420
2419
  const timing = buildRunTimingSnapshot(run, config);
2420
+ const metrics = buildTaskExecutionMetrics(run);
2421
2421
  return {
2422
2422
  runId: run.runId,
2423
2423
  status: run.status,
@@ -2444,7 +2444,11 @@ async function main() {
2444
2444
  cancelRequestedAt: run.cancelRequestedAt ?? null,
2445
2445
  elapsedMs: timing.elapsedMs,
2446
2446
  idleMs: timing.idleMs,
2447
- timeoutKind: timing.timeoutKind
2447
+ timeoutKind: timing.timeoutKind,
2448
+ metrics: metrics ? {
2449
+ ...metrics,
2450
+ display: formatExecutionMetricsCompact(metrics)
2451
+ } : null
2448
2452
  };
2449
2453
  })
2450
2454
  };
@@ -3119,6 +3123,10 @@ function renderTaskResultReport(input) {
3119
3123
  if (latestRun.endedAt) {
3120
3124
  lines.push(`Ended At: ${latestRun.endedAt}`);
3121
3125
  }
3126
+ const metrics = formatExecutionMetricsCompact(buildTaskExecutionMetrics(latestRun));
3127
+ if (metrics) {
3128
+ lines.push(`Metrics: ${metrics}`);
3129
+ }
3122
3130
  }
3123
3131
  lines.push("");
3124
3132
  lines.push("Summary");
@@ -3142,6 +3150,10 @@ function renderTaskResultReport(input) {
3142
3150
  lines.push("Delivery");
3143
3151
  lines.push(`Outcome: ${input.deliveryBundle.outcome}`);
3144
3152
  lines.push(`Decision: ${input.deliveryBundle.summary.decision}`);
3153
+ const metrics = formatExecutionMetricsCompact(input.deliveryBundle.metrics);
3154
+ if (metrics) {
3155
+ lines.push(`Metrics: ${metrics}`);
3156
+ }
3145
3157
  if (input.deliveryBundle.warnings?.length) {
3146
3158
  lines.push(`Warnings: ${input.deliveryBundle.warnings.join(", ")}`);
3147
3159
  }